Revert "[wasm] Remove finisher task"
This reverts commit ac2fb66b65
.
Reason for revert: Flakily crashes on several bots:
https://ci.chromium.org/p/v8/builders/luci.v8.ci/V8%20Win32/18524
https://ci.chromium.org/p/v8/builders/luci.v8.ci/V8%20Win64%20-%20msvc/6824
https://ci.chromium.org/p/v8/builders/luci.v8.ci/V8%20Linux64%20-%20internal%20snapshot/19766
Original change's description:
> [wasm] Remove finisher task
>
> This removes the finisher task and instead finishes compilation units
> from the background.
> It also changes ownership of the AsyncCompileJob to be shared among all
> tasks that still operate on it. The AsyncCompileJob dies when the last
> reference dies.
>
> R=ahaas@chromium.org
> CC=mstarzinger@chromium.org
>
> Bug: v8:7921, v8:8423
> Change-Id: Id09378327dfc146459ef41bc97176a8716756ae4
> Cq-Include-Trybots: luci.v8.try:v8_linux64_tsan_rel
> Reviewed-on: https://chromium-review.googlesource.com/c/1335553
> Reviewed-by: Andreas Haas <ahaas@chromium.org>
> Commit-Queue: Clemens Hammacher <clemensh@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#58630}
TBR=ahaas@chromium.org,clemensh@chromium.org
Change-Id: I6b332b66adaec8f713fb31f4c8517cae7ebb4645
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: v8:7921, v8:8423
Cq-Include-Trybots: luci.v8.try:v8_linux64_tsan_rel
Reviewed-on: https://chromium-review.googlesource.com/c/1400420
Reviewed-by: Michael Achenbach <machenbach@chromium.org>
Commit-Queue: Michael Achenbach <machenbach@chromium.org>
Cr-Commit-Position: refs/heads/master@{#58634}
This commit is contained in:
parent
2dfba659dd
commit
58ca563860
@ -8629,7 +8629,7 @@ int Isolate::ContextDisposedNotification(bool dependant_context) {
|
|||||||
if (!dependant_context) {
|
if (!dependant_context) {
|
||||||
// We left the current context, we can abort all WebAssembly compilations on
|
// We left the current context, we can abort all WebAssembly compilations on
|
||||||
// that isolate.
|
// that isolate.
|
||||||
isolate->wasm_engine()->AbortCompileJobsOnIsolate(isolate);
|
isolate->wasm_engine()->DeleteCompileJobsOnIsolate(isolate);
|
||||||
}
|
}
|
||||||
// TODO(ahaas): move other non-heap activity out of the heap call.
|
// TODO(ahaas): move other non-heap activity out of the heap call.
|
||||||
return isolate->heap()->NotifyContextDisposed(dependant_context);
|
return isolate->heap()->NotifyContextDisposed(dependant_context);
|
||||||
|
@ -2839,7 +2839,7 @@ void Isolate::Deinit() {
|
|||||||
|
|
||||||
debug()->Unload();
|
debug()->Unload();
|
||||||
|
|
||||||
wasm_engine()->AbortCompileJobsOnIsolate(this);
|
wasm_engine()->DeleteCompileJobsOnIsolate(this);
|
||||||
|
|
||||||
if (concurrent_recompilation_enabled()) {
|
if (concurrent_recompilation_enabled()) {
|
||||||
optimizing_compile_dispatcher_->Stop();
|
optimizing_compile_dispatcher_->Stop();
|
||||||
|
@ -93,7 +93,7 @@ class CompilationState {
|
|||||||
using callback_t = std::function<void(CompilationEvent, const ResultBase*)>;
|
using callback_t = std::function<void(CompilationEvent, const ResultBase*)>;
|
||||||
~CompilationState();
|
~CompilationState();
|
||||||
|
|
||||||
void AbortCompilation();
|
void CancelAndWait();
|
||||||
|
|
||||||
void SetError(uint32_t func_index, const ResultBase& error_result);
|
void SetError(uint32_t func_index, const ResultBase& error_result);
|
||||||
|
|
||||||
|
@ -67,7 +67,7 @@ class 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
|
||||||
// this before destructing this object.
|
// this before destructing this object.
|
||||||
void AbortCompilation();
|
void CancelAndWait();
|
||||||
|
|
||||||
// Set the number of compilations unit expected to be executed. Needs to be
|
// Set the number of compilations unit expected to be executed. Needs to be
|
||||||
// set before {AddCompilationUnits} is run, which triggers background
|
// set before {AddCompilationUnits} is run, which triggers background
|
||||||
@ -83,6 +83,9 @@ class CompilationStateImpl {
|
|||||||
std::vector<std::unique_ptr<WasmCompilationUnit>>& baseline_units,
|
std::vector<std::unique_ptr<WasmCompilationUnit>>& baseline_units,
|
||||||
std::vector<std::unique_ptr<WasmCompilationUnit>>& tiering_units);
|
std::vector<std::unique_ptr<WasmCompilationUnit>>& tiering_units);
|
||||||
std::unique_ptr<WasmCompilationUnit> GetNextCompilationUnit();
|
std::unique_ptr<WasmCompilationUnit> GetNextCompilationUnit();
|
||||||
|
std::unique_ptr<WasmCompilationUnit> GetNextExecutedUnit();
|
||||||
|
|
||||||
|
bool HasCompilationUnitToFinish();
|
||||||
|
|
||||||
void OnFinishedUnit(ExecutionTier);
|
void OnFinishedUnit(ExecutionTier);
|
||||||
void ScheduleCodeLogging(WasmCode*);
|
void ScheduleCodeLogging(WasmCode*);
|
||||||
@ -90,6 +93,10 @@ class CompilationStateImpl {
|
|||||||
void OnBackgroundTaskStopped(const WasmFeatures& detected);
|
void OnBackgroundTaskStopped(const WasmFeatures& detected);
|
||||||
void PublishDetectedFeatures(Isolate* isolate, const WasmFeatures& detected);
|
void PublishDetectedFeatures(Isolate* isolate, const WasmFeatures& detected);
|
||||||
void RestartBackgroundTasks(size_t max = std::numeric_limits<size_t>::max());
|
void RestartBackgroundTasks(size_t max = std::numeric_limits<size_t>::max());
|
||||||
|
// Only one foreground thread (finisher) is allowed to run at a time.
|
||||||
|
// {SetFinisherIsRunning} returns whether the flag changed its state.
|
||||||
|
bool SetFinisherIsRunning(bool value);
|
||||||
|
void ScheduleFinisherTask();
|
||||||
|
|
||||||
void Abort();
|
void Abort();
|
||||||
|
|
||||||
@ -207,6 +214,11 @@ class CompilationStateImpl {
|
|||||||
|
|
||||||
void NotifyOnEvent(CompilationEvent event, const VoidResult* error_result);
|
void NotifyOnEvent(CompilationEvent event, const VoidResult* error_result);
|
||||||
|
|
||||||
|
std::vector<std::unique_ptr<WasmCompilationUnit>>& finish_units() {
|
||||||
|
return baseline_compilation_finished() ? tiering_finish_units_
|
||||||
|
: baseline_finish_units_;
|
||||||
|
}
|
||||||
|
|
||||||
// TODO(mstarzinger): Get rid of the Isolate field to make sure the
|
// TODO(mstarzinger): Get rid of the Isolate field to make sure the
|
||||||
// {CompilationStateImpl} can be shared across multiple Isolates.
|
// {CompilationStateImpl} can be shared across multiple Isolates.
|
||||||
Isolate* const isolate_;
|
Isolate* const isolate_;
|
||||||
@ -233,8 +245,12 @@ class CompilationStateImpl {
|
|||||||
std::vector<std::unique_ptr<WasmCompilationUnit>> baseline_compilation_units_;
|
std::vector<std::unique_ptr<WasmCompilationUnit>> baseline_compilation_units_;
|
||||||
std::vector<std::unique_ptr<WasmCompilationUnit>> tiering_compilation_units_;
|
std::vector<std::unique_ptr<WasmCompilationUnit>> tiering_compilation_units_;
|
||||||
|
|
||||||
|
bool finisher_is_running_ = false;
|
||||||
size_t num_background_tasks_ = 0;
|
size_t num_background_tasks_ = 0;
|
||||||
|
|
||||||
|
std::vector<std::unique_ptr<WasmCompilationUnit>> baseline_finish_units_;
|
||||||
|
std::vector<std::unique_ptr<WasmCompilationUnit>> tiering_finish_units_;
|
||||||
|
|
||||||
// Features detected to be used in this module. Features can be detected
|
// Features detected to be used in this module. Features can be detected
|
||||||
// as a module is being compiled.
|
// as a module is being compiled.
|
||||||
WasmFeatures detected_features_ = kNoWasmFeatures;
|
WasmFeatures detected_features_ = kNoWasmFeatures;
|
||||||
@ -473,7 +489,7 @@ const CompilationStateImpl* Impl(const CompilationState* compilation_state) {
|
|||||||
|
|
||||||
CompilationState::~CompilationState() { Impl(this)->~CompilationStateImpl(); }
|
CompilationState::~CompilationState() { Impl(this)->~CompilationStateImpl(); }
|
||||||
|
|
||||||
void CompilationState::AbortCompilation() { Impl(this)->AbortCompilation(); }
|
void CompilationState::CancelAndWait() { Impl(this)->CancelAndWait(); }
|
||||||
|
|
||||||
void CompilationState::SetError(uint32_t func_index,
|
void CompilationState::SetError(uint32_t func_index,
|
||||||
const ResultBase& error_result) {
|
const ResultBase& error_result) {
|
||||||
@ -660,8 +676,15 @@ bool in_bounds(uint32_t offset, size_t size, size_t upper) {
|
|||||||
using WasmInstanceMap =
|
using WasmInstanceMap =
|
||||||
IdentityMap<Handle<WasmInstanceObject>, FreeStoreAllocationPolicy>;
|
IdentityMap<Handle<WasmInstanceObject>, FreeStoreAllocationPolicy>;
|
||||||
|
|
||||||
|
double MonotonicallyIncreasingTimeInMs() {
|
||||||
|
return V8::GetCurrentPlatform()->MonotonicallyIncreasingTime() *
|
||||||
|
base::Time::kMillisecondsPerSecond;
|
||||||
|
}
|
||||||
|
|
||||||
// Run by each compilation task and by the main thread (i.e. in both
|
// Run by each compilation task and by the main thread (i.e. in both
|
||||||
// foreground and background threads).
|
// foreground and background threads). The no_finisher_callback is called
|
||||||
|
// within the result_mutex_ lock when no finishing task is running, i.e. when
|
||||||
|
// the finisher_is_running_ flag is not set.
|
||||||
bool FetchAndExecuteCompilationUnit(CompilationEnv* env,
|
bool FetchAndExecuteCompilationUnit(CompilationEnv* env,
|
||||||
CompilationStateImpl* compilation_state,
|
CompilationStateImpl* compilation_state,
|
||||||
WasmFeatures* detected,
|
WasmFeatures* detected,
|
||||||
@ -698,6 +721,15 @@ void InitializeCompilationUnits(NativeModule* native_module,
|
|||||||
builder.Commit();
|
builder.Commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FinishCompilationUnits(CompilationStateImpl* compilation_state) {
|
||||||
|
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("v8.wasm"), "FinishCompilationUnits");
|
||||||
|
while (!compilation_state->failed()) {
|
||||||
|
std::unique_ptr<WasmCompilationUnit> unit =
|
||||||
|
compilation_state->GetNextExecutedUnit();
|
||||||
|
if (unit == nullptr) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void CompileInParallel(Isolate* isolate, NativeModule* native_module) {
|
void CompileInParallel(Isolate* isolate, NativeModule* native_module) {
|
||||||
// Data structures for the parallel compilation.
|
// Data structures for the parallel compilation.
|
||||||
|
|
||||||
@ -710,6 +742,12 @@ void CompileInParallel(Isolate* isolate, NativeModule* native_module) {
|
|||||||
// the background threads.
|
// the background threads.
|
||||||
// 2) The background threads and the main thread pick one compilation unit at
|
// 2) The background threads and the main thread pick one compilation unit at
|
||||||
// a time and execute the parallel phase of the compilation unit.
|
// a time and execute the parallel phase of the compilation unit.
|
||||||
|
// 3) After the parallel phase of all compilation units has started, the
|
||||||
|
// main thread continues to finish all compilation units as long as
|
||||||
|
// baseline-compilation units are left to be processed.
|
||||||
|
// 4) If tier-up is enabled, the main thread restarts background tasks
|
||||||
|
// that take care of compiling and finishing the top-tier compilation
|
||||||
|
// units.
|
||||||
|
|
||||||
// Turn on the {CanonicalHandleScope} so that the background threads can
|
// Turn on the {CanonicalHandleScope} so that the background threads can
|
||||||
// use the node cache.
|
// use the node cache.
|
||||||
@ -717,6 +755,10 @@ void CompileInParallel(Isolate* isolate, NativeModule* native_module) {
|
|||||||
|
|
||||||
CompilationStateImpl* compilation_state =
|
CompilationStateImpl* compilation_state =
|
||||||
Impl(native_module->compilation_state());
|
Impl(native_module->compilation_state());
|
||||||
|
// Make sure that no foreground task is spawned for finishing
|
||||||
|
// the compilation units. This foreground thread will be
|
||||||
|
// responsible for finishing compilation.
|
||||||
|
compilation_state->SetFinisherIsRunning(true);
|
||||||
uint32_t num_wasm_functions =
|
uint32_t num_wasm_functions =
|
||||||
native_module->num_functions() - native_module->num_imported_functions();
|
native_module->num_functions() - native_module->num_imported_functions();
|
||||||
compilation_state->SetNumberOfFunctionsToCompile(num_wasm_functions);
|
compilation_state->SetNumberOfFunctionsToCompile(num_wasm_functions);
|
||||||
@ -732,19 +774,38 @@ void CompileInParallel(Isolate* isolate, NativeModule* native_module) {
|
|||||||
// a time and execute the parallel phase of the compilation unit.
|
// a time and execute the parallel phase of the compilation unit.
|
||||||
WasmFeatures detected_features;
|
WasmFeatures detected_features;
|
||||||
CompilationEnv env = native_module->CreateCompilationEnv();
|
CompilationEnv env = native_module->CreateCompilationEnv();
|
||||||
// TODO(wasm): This might already execute TurboFan units on the main thread,
|
while (FetchAndExecuteCompilationUnit(&env, compilation_state,
|
||||||
// while waiting for baseline compilation to finish. This can introduce
|
&detected_features,
|
||||||
// additional delay.
|
isolate->counters()) &&
|
||||||
// TODO(wasm): This is a busy-wait loop once all units have started executing
|
|
||||||
// in background threads. Replace by a semaphore / barrier.
|
|
||||||
while (!compilation_state->failed() &&
|
|
||||||
!compilation_state->baseline_compilation_finished()) {
|
!compilation_state->baseline_compilation_finished()) {
|
||||||
FetchAndExecuteCompilationUnit(&env, compilation_state, &detected_features,
|
// TODO(clemensh): Refactor ownership of the AsyncCompileJob and remove
|
||||||
isolate->counters());
|
// this.
|
||||||
|
FinishCompilationUnits(compilation_state);
|
||||||
|
|
||||||
|
if (compilation_state->failed()) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!compilation_state->failed()) {
|
||||||
|
// 3) After the parallel phase of all compilation units has started, the
|
||||||
|
// main thread continues to finish compilation units as long as
|
||||||
|
// baseline compilation units are left to be processed. If compilation
|
||||||
|
// already failed, all background tasks have already been canceled
|
||||||
|
// in {FinishCompilationUnits}, and there are no units to finish.
|
||||||
|
FinishCompilationUnits(compilation_state);
|
||||||
|
|
||||||
|
if (compilation_state->baseline_compilation_finished()) break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Publish features from the foreground and background tasks.
|
// Publish features from the foreground and background tasks.
|
||||||
compilation_state->PublishDetectedFeatures(isolate, detected_features);
|
compilation_state->PublishDetectedFeatures(isolate, detected_features);
|
||||||
|
|
||||||
|
// 4) If tiering-compilation is enabled, we need to set the finisher
|
||||||
|
// to false, such that the background threads will spawn a foreground
|
||||||
|
// thread to finish the top-tier compilation units.
|
||||||
|
if (!compilation_state->failed() &&
|
||||||
|
compilation_state->compile_mode() == CompileMode::kTiering) {
|
||||||
|
compilation_state->SetFinisherIsRunning(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CompileSequentially(Isolate* isolate, NativeModule* native_module,
|
void CompileSequentially(Isolate* isolate, NativeModule* native_module,
|
||||||
@ -842,6 +903,62 @@ void CompileNativeModule(Isolate* isolate, ErrorThrower* thrower,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The runnable task that finishes compilation in foreground (e.g. updating
|
||||||
|
// the NativeModule, the code table, etc.).
|
||||||
|
class FinishCompileTask : public CancelableTask {
|
||||||
|
public:
|
||||||
|
explicit FinishCompileTask(CompilationStateImpl* compilation_state,
|
||||||
|
CancelableTaskManager* task_manager)
|
||||||
|
: CancelableTask(task_manager), compilation_state_(compilation_state) {}
|
||||||
|
|
||||||
|
void RunInternal() override {
|
||||||
|
Isolate* isolate = compilation_state_->isolate();
|
||||||
|
HandleScope scope(isolate);
|
||||||
|
SaveContext saved_context(isolate);
|
||||||
|
isolate->set_context(Context());
|
||||||
|
|
||||||
|
TRACE_COMPILE("(4a) Finishing compilation units...\n");
|
||||||
|
if (compilation_state_->failed()) {
|
||||||
|
compilation_state_->SetFinisherIsRunning(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We execute for 1 ms and then reschedule the task, same as the GC.
|
||||||
|
double deadline = MonotonicallyIncreasingTimeInMs() + 1.0;
|
||||||
|
while (true) {
|
||||||
|
compilation_state_->RestartBackgroundTasks();
|
||||||
|
|
||||||
|
std::unique_ptr<WasmCompilationUnit> unit =
|
||||||
|
compilation_state_->GetNextExecutedUnit();
|
||||||
|
|
||||||
|
if (unit == nullptr) {
|
||||||
|
// It might happen that a background task just scheduled a unit to be
|
||||||
|
// finished, but did not start a finisher task since the flag was still
|
||||||
|
// set. Check for this case, and continue if there is more work.
|
||||||
|
compilation_state_->SetFinisherIsRunning(false);
|
||||||
|
if (compilation_state_->HasCompilationUnitToFinish() &&
|
||||||
|
compilation_state_->SetFinisherIsRunning(true)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (compilation_state_->failed()) break;
|
||||||
|
|
||||||
|
if (deadline < MonotonicallyIncreasingTimeInMs()) {
|
||||||
|
// We reached the deadline. We reschedule this task and return
|
||||||
|
// immediately. Since we rescheduled this task already, we do not set
|
||||||
|
// the FinisherIsRunning flag to false.
|
||||||
|
compilation_state_->ScheduleFinisherTask();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
CompilationStateImpl* compilation_state_;
|
||||||
|
};
|
||||||
|
|
||||||
// The runnable task that performs compilations in the background.
|
// The runnable task that performs compilations in the background.
|
||||||
class BackgroundCompileTask : public CancelableTask {
|
class BackgroundCompileTask : public CancelableTask {
|
||||||
public:
|
public:
|
||||||
@ -2296,18 +2413,14 @@ void AsyncCompileJob::Start() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void AsyncCompileJob::Abort() {
|
void AsyncCompileJob::Abort() {
|
||||||
background_task_manager_.CancelAndWait();
|
// Removing this job will trigger the destructor, which will cancel all
|
||||||
if (native_module_) Impl(native_module_->compilation_state())->Abort();
|
// compilation.
|
||||||
// Tell the streaming decoder that compilation aborted.
|
isolate_->wasm_engine()->RemoveCompileJob(this);
|
||||||
// TODO(ahaas): Is this notification really necessary? Check
|
|
||||||
// https://crbug.com/888170.
|
|
||||||
if (stream_) stream_->NotifyCompilationEnded();
|
|
||||||
CancelPendingForegroundTask();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class AsyncStreamingProcessor final : public StreamingProcessor {
|
class AsyncStreamingProcessor final : public StreamingProcessor {
|
||||||
public:
|
public:
|
||||||
explicit AsyncStreamingProcessor(std::shared_ptr<AsyncCompileJob> job);
|
explicit AsyncStreamingProcessor(AsyncCompileJob* job);
|
||||||
|
|
||||||
bool ProcessModuleHeader(Vector<const uint8_t> bytes,
|
bool ProcessModuleHeader(Vector<const uint8_t> bytes,
|
||||||
uint32_t offset) override;
|
uint32_t offset) override;
|
||||||
@ -2339,22 +2452,28 @@ class AsyncStreamingProcessor final : public StreamingProcessor {
|
|||||||
void CommitCompilationUnits();
|
void CommitCompilationUnits();
|
||||||
|
|
||||||
ModuleDecoder decoder_;
|
ModuleDecoder decoder_;
|
||||||
std::shared_ptr<AsyncCompileJob> job_;
|
AsyncCompileJob* job_;
|
||||||
std::unique_ptr<CompilationUnitBuilder> compilation_unit_builder_;
|
std::unique_ptr<CompilationUnitBuilder> compilation_unit_builder_;
|
||||||
uint32_t next_function_ = 0;
|
uint32_t next_function_ = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::shared_ptr<StreamingDecoder> AsyncCompileJob::CreateStreamingDecoder() {
|
std::shared_ptr<StreamingDecoder> AsyncCompileJob::CreateStreamingDecoder() {
|
||||||
DCHECK_NULL(stream_);
|
DCHECK_NULL(stream_);
|
||||||
stream_ = std::make_shared<StreamingDecoder>(
|
stream_.reset(
|
||||||
base::make_unique<AsyncStreamingProcessor>(shared_from_this()));
|
new StreamingDecoder(base::make_unique<AsyncStreamingProcessor>(this)));
|
||||||
return stream_;
|
return stream_;
|
||||||
}
|
}
|
||||||
|
|
||||||
AsyncCompileJob::~AsyncCompileJob() {
|
AsyncCompileJob::~AsyncCompileJob() {
|
||||||
background_task_manager_.CancelAndWait();
|
background_task_manager_.CancelAndWait();
|
||||||
|
if (native_module_) Impl(native_module_->compilation_state())->Abort();
|
||||||
|
// Tell the streaming decoder that the AsyncCompileJob is not available
|
||||||
|
// anymore.
|
||||||
|
// TODO(ahaas): Is this notification really necessary? Check
|
||||||
|
// https://crbug.com/888170.
|
||||||
|
if (stream_) stream_->NotifyCompilationEnded();
|
||||||
|
CancelPendingForegroundTask();
|
||||||
for (auto d : deferred_handles_) delete d;
|
for (auto d : deferred_handles_) delete d;
|
||||||
isolate_->wasm_engine()->RemoveCompileJob(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AsyncCompileJob::PrepareRuntimeObjects(
|
void AsyncCompileJob::PrepareRuntimeObjects(
|
||||||
@ -2424,19 +2543,19 @@ void AsyncCompileJob::FinishCompile(bool compile_wrappers) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void AsyncCompileJob::AsyncCompileFailed(Handle<Object> error_reason) {
|
void AsyncCompileJob::AsyncCompileFailed(Handle<Object> error_reason) {
|
||||||
if (stream_) stream_->NotifyCompilationEnded();
|
// {job} keeps the {this} pointer alive.
|
||||||
|
std::shared_ptr<AsyncCompileJob> job =
|
||||||
|
isolate_->wasm_engine()->RemoveCompileJob(this);
|
||||||
resolver_->OnCompilationFailed(error_reason);
|
resolver_->OnCompilationFailed(error_reason);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AsyncCompileJob::AsyncCompileSucceeded(Handle<WasmModuleObject> result) {
|
void AsyncCompileJob::AsyncCompileSucceeded(Handle<WasmModuleObject> result) {
|
||||||
if (stream_) stream_->NotifyCompilationEnded();
|
|
||||||
resolver_->OnCompilationSucceeded(result);
|
resolver_->OnCompilationSucceeded(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
class AsyncCompileJob::CompilationStateCallback {
|
class AsyncCompileJob::CompilationStateCallback {
|
||||||
public:
|
public:
|
||||||
explicit CompilationStateCallback(std::shared_ptr<AsyncCompileJob> job)
|
explicit CompilationStateCallback(AsyncCompileJob* job) : job_(job) {}
|
||||||
: job_(std::move(job)) {}
|
|
||||||
|
|
||||||
void operator()(CompilationEvent event, const ResultBase* error_result) {
|
void operator()(CompilationEvent event, const ResultBase* error_result) {
|
||||||
// This callback is only being called from a foreground task.
|
// This callback is only being called from a foreground task.
|
||||||
@ -2451,10 +2570,21 @@ class AsyncCompileJob::CompilationStateCallback {
|
|||||||
break;
|
break;
|
||||||
case CompilationEvent::kFinishedTopTierCompilation:
|
case CompilationEvent::kFinishedTopTierCompilation:
|
||||||
DCHECK_EQ(CompilationEvent::kFinishedBaselineCompilation, last_event_);
|
DCHECK_EQ(CompilationEvent::kFinishedBaselineCompilation, last_event_);
|
||||||
|
// If a foreground task or a finisher is pending, we rely on
|
||||||
|
// FinishModule to remove the job.
|
||||||
|
if (!job_->pending_foreground_task_ &&
|
||||||
|
job_->outstanding_finishers_.load() == 0) {
|
||||||
|
job_->isolate_->wasm_engine()->RemoveCompileJob(job_);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case CompilationEvent::kFailedCompilation:
|
case CompilationEvent::kFailedCompilation:
|
||||||
DCHECK(!last_event_.has_value());
|
DCHECK(!last_event_.has_value());
|
||||||
DCHECK_NOT_NULL(error_result);
|
DCHECK_NOT_NULL(error_result);
|
||||||
|
// Tier-up compilation should not fail if baseline compilation
|
||||||
|
// did not fail.
|
||||||
|
DCHECK(!Impl(job_->native_module_->compilation_state())
|
||||||
|
->baseline_compilation_finished());
|
||||||
|
|
||||||
{
|
{
|
||||||
SaveContext saved_context(job_->isolate());
|
SaveContext saved_context(job_->isolate());
|
||||||
job_->isolate()->set_context(*job_->native_context_);
|
job_->isolate()->set_context(*job_->native_context_);
|
||||||
@ -2462,7 +2592,11 @@ class AsyncCompileJob::CompilationStateCallback {
|
|||||||
thrower.CompileFailed(*error_result);
|
thrower.CompileFailed(*error_result);
|
||||||
Handle<Object> error = thrower.Reify();
|
Handle<Object> error = thrower.Reify();
|
||||||
|
|
||||||
job_->AsyncCompileFailed(error);
|
DeferredHandleScope deferred(job_->isolate());
|
||||||
|
error = handle(*error, job_->isolate());
|
||||||
|
job_->deferred_handles_.push_back(deferred.Detach());
|
||||||
|
|
||||||
|
job_->DoSync<CompileFailed, kUseExistingForegroundTask>(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@ -2475,7 +2609,7 @@ class AsyncCompileJob::CompilationStateCallback {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::shared_ptr<AsyncCompileJob> job_;
|
AsyncCompileJob* job_;
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
base::Optional<CompilationEvent> last_event_;
|
base::Optional<CompilationEvent> last_event_;
|
||||||
#endif
|
#endif
|
||||||
@ -2487,7 +2621,7 @@ class AsyncCompileJob::CompileStep {
|
|||||||
public:
|
public:
|
||||||
virtual ~CompileStep() = default;
|
virtual ~CompileStep() = default;
|
||||||
|
|
||||||
void Run(const std::shared_ptr<AsyncCompileJob>& job, bool on_foreground) {
|
void Run(AsyncCompileJob* job, bool on_foreground) {
|
||||||
if (on_foreground) {
|
if (on_foreground) {
|
||||||
HandleScope scope(job->isolate_);
|
HandleScope scope(job->isolate_);
|
||||||
SaveContext saved_context(job->isolate_);
|
SaveContext saved_context(job->isolate_);
|
||||||
@ -2498,12 +2632,8 @@ class AsyncCompileJob::CompileStep {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void RunInForeground(const std::shared_ptr<AsyncCompileJob>&) {
|
virtual void RunInForeground(AsyncCompileJob*) { UNREACHABLE(); }
|
||||||
UNREACHABLE();
|
virtual void RunInBackground(AsyncCompileJob*) { UNREACHABLE(); }
|
||||||
}
|
|
||||||
virtual void RunInBackground(const std::shared_ptr<AsyncCompileJob>&) {
|
|
||||||
UNREACHABLE();
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class AsyncCompileJob::CompileTask : public CancelableTask {
|
class AsyncCompileJob::CompileTask : public CancelableTask {
|
||||||
@ -2515,7 +2645,7 @@ class AsyncCompileJob::CompileTask : public CancelableTask {
|
|||||||
// their own task manager.
|
// their own task manager.
|
||||||
: CancelableTask(on_foreground ? job->isolate_->cancelable_task_manager()
|
: CancelableTask(on_foreground ? job->isolate_->cancelable_task_manager()
|
||||||
: &job->background_task_manager_),
|
: &job->background_task_manager_),
|
||||||
job_(job->shared_from_this()),
|
job_(job),
|
||||||
on_foreground_(on_foreground) {}
|
on_foreground_(on_foreground) {}
|
||||||
|
|
||||||
~CompileTask() override {
|
~CompileTask() override {
|
||||||
@ -2537,10 +2667,9 @@ class AsyncCompileJob::CompileTask : public CancelableTask {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Compile tasks (foreground and background) keep the {AsyncCompileJob} alive
|
// {job_} will be cleared to cancel a pending task.
|
||||||
// via shared_ptr. It will be cleared to cancel a pending task.
|
AsyncCompileJob* job_;
|
||||||
std::shared_ptr<AsyncCompileJob> job_;
|
bool on_foreground_;
|
||||||
const bool on_foreground_;
|
|
||||||
|
|
||||||
void ResetPendingForegroundTask() const {
|
void ResetPendingForegroundTask() const {
|
||||||
DCHECK_EQ(this, job_->pending_foreground_task_);
|
DCHECK_EQ(this, job_->pending_foreground_task_);
|
||||||
@ -2615,7 +2744,7 @@ class AsyncCompileJob::DecodeModule : public AsyncCompileJob::CompileStep {
|
|||||||
public:
|
public:
|
||||||
explicit DecodeModule(Counters* counters) : counters_(counters) {}
|
explicit DecodeModule(Counters* counters) : counters_(counters) {}
|
||||||
|
|
||||||
void RunInBackground(const std::shared_ptr<AsyncCompileJob>& job) override {
|
void RunInBackground(AsyncCompileJob* job) override {
|
||||||
ModuleResult result;
|
ModuleResult result;
|
||||||
{
|
{
|
||||||
DisallowHandleAllocation no_handle;
|
DisallowHandleAllocation no_handle;
|
||||||
@ -2651,10 +2780,11 @@ class AsyncCompileJob::DecodeFail : public CompileStep {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
ModuleResult result_;
|
ModuleResult result_;
|
||||||
void RunInForeground(const std::shared_ptr<AsyncCompileJob>& job) override {
|
void RunInForeground(AsyncCompileJob* job) override {
|
||||||
TRACE_COMPILE("(1b) Decoding failed.\n");
|
TRACE_COMPILE("(1b) Decoding failed.\n");
|
||||||
ErrorThrower thrower(job->isolate_, "AsyncCompile");
|
ErrorThrower thrower(job->isolate_, "AsyncCompile");
|
||||||
thrower.CompileFailed("Wasm decoding failed", result_);
|
thrower.CompileFailed("Wasm decoding failed", result_);
|
||||||
|
// {job_} is deleted in AsyncCompileFailed, therefore the {return}.
|
||||||
return job->AsyncCompileFailed(thrower.Reify());
|
return job->AsyncCompileFailed(thrower.Reify());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -2672,7 +2802,7 @@ class AsyncCompileJob::PrepareAndStartCompile : public CompileStep {
|
|||||||
std::shared_ptr<const WasmModule> module_;
|
std::shared_ptr<const WasmModule> module_;
|
||||||
bool start_compilation_;
|
bool start_compilation_;
|
||||||
|
|
||||||
void RunInForeground(const std::shared_ptr<AsyncCompileJob>& job) override {
|
void RunInForeground(AsyncCompileJob* job) override {
|
||||||
TRACE_COMPILE("(2) Prepare and start compile...\n");
|
TRACE_COMPILE("(2) Prepare and start compile...\n");
|
||||||
|
|
||||||
// Make sure all compilation tasks stopped running. Decoding (async step)
|
// Make sure all compilation tasks stopped running. Decoding (async step)
|
||||||
@ -2708,13 +2838,30 @@ class AsyncCompileJob::PrepareAndStartCompile : public CompileStep {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//==========================================================================
|
||||||
|
// Step 4b (sync): Compilation failed. Reject Promise.
|
||||||
|
//==========================================================================
|
||||||
|
class AsyncCompileJob::CompileFailed : public CompileStep {
|
||||||
|
public:
|
||||||
|
explicit CompileFailed(Handle<Object> error_reason)
|
||||||
|
: error_reason_(error_reason) {}
|
||||||
|
|
||||||
|
void RunInForeground(AsyncCompileJob* job) override {
|
||||||
|
TRACE_COMPILE("(4b) Compilation Failed...\n");
|
||||||
|
return job->AsyncCompileFailed(error_reason_);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Handle<Object> error_reason_;
|
||||||
|
};
|
||||||
|
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
// Step 5 (sync): Compile JS->wasm wrappers.
|
// Step 5 (sync): Compile JS->wasm wrappers.
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
class AsyncCompileJob::CompileWrappers : public CompileStep {
|
class AsyncCompileJob::CompileWrappers : public CompileStep {
|
||||||
// TODO(wasm): Compile all wrappers here, including the start function wrapper
|
// TODO(wasm): Compile all wrappers here, including the start function wrapper
|
||||||
// and the wrappers for the function table elements.
|
// and the wrappers for the function table elements.
|
||||||
void RunInForeground(const std::shared_ptr<AsyncCompileJob>& job) override {
|
void RunInForeground(AsyncCompileJob* job) override {
|
||||||
TRACE_COMPILE("(5) Compile wrappers...\n");
|
TRACE_COMPILE("(5) Compile wrappers...\n");
|
||||||
// Compile JS->wasm wrappers for exported functions.
|
// Compile JS->wasm wrappers for exported functions.
|
||||||
CompileJsToWasmWrappers(
|
CompileJsToWasmWrappers(
|
||||||
@ -2728,20 +2875,33 @@ class AsyncCompileJob::CompileWrappers : public CompileStep {
|
|||||||
// Step 6 (sync): Finish the module and resolve the promise.
|
// Step 6 (sync): Finish the module and resolve the promise.
|
||||||
//==========================================================================
|
//==========================================================================
|
||||||
class AsyncCompileJob::FinishModule : public CompileStep {
|
class AsyncCompileJob::FinishModule : public CompileStep {
|
||||||
void RunInForeground(const std::shared_ptr<AsyncCompileJob>& job) override {
|
void RunInForeground(AsyncCompileJob* job) override {
|
||||||
TRACE_COMPILE("(6) Finish module...\n");
|
TRACE_COMPILE("(6) Finish module...\n");
|
||||||
job->AsyncCompileSucceeded(job->module_object_);
|
job->AsyncCompileSucceeded(job->module_object_);
|
||||||
|
|
||||||
|
size_t num_functions = job->native_module_->num_functions() -
|
||||||
|
job->native_module_->num_imported_functions();
|
||||||
|
auto* compilation_state = Impl(job->native_module_->compilation_state());
|
||||||
|
if (compilation_state->compile_mode() == CompileMode::kRegular ||
|
||||||
|
num_functions == 0) {
|
||||||
|
// If we do not tier up, the async compile job is done here and
|
||||||
|
// can be deleted.
|
||||||
|
job->isolate_->wasm_engine()->RemoveCompileJob(job);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
DCHECK_EQ(CompileMode::kTiering, compilation_state->compile_mode());
|
||||||
|
if (compilation_state->baseline_compilation_finished()) {
|
||||||
|
job->isolate_->wasm_engine()->RemoveCompileJob(job);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
AsyncStreamingProcessor::AsyncStreamingProcessor(
|
AsyncStreamingProcessor::AsyncStreamingProcessor(AsyncCompileJob* job)
|
||||||
std::shared_ptr<AsyncCompileJob> job)
|
|
||||||
: decoder_(job->enabled_features_),
|
: decoder_(job->enabled_features_),
|
||||||
job_(std::move(job)),
|
job_(job),
|
||||||
compilation_unit_builder_(nullptr) {}
|
compilation_unit_builder_(nullptr) {}
|
||||||
|
|
||||||
void AsyncStreamingProcessor::FinishAsyncCompileJobWithError(ResultBase error) {
|
void AsyncStreamingProcessor::FinishAsyncCompileJobWithError(ResultBase error) {
|
||||||
TRACE_STREAMING("Finish streaming with error.\n");
|
|
||||||
DCHECK(error.failed());
|
DCHECK(error.failed());
|
||||||
// Make sure all background tasks stopped executing before we change the state
|
// Make sure all background tasks stopped executing before we change the state
|
||||||
// of the AsyncCompileJob to DecodeFail.
|
// of the AsyncCompileJob to DecodeFail.
|
||||||
@ -2954,14 +3114,13 @@ CompilationStateImpl::CompilationStateImpl(internal::Isolate* isolate,
|
|||||||
}
|
}
|
||||||
|
|
||||||
CompilationStateImpl::~CompilationStateImpl() {
|
CompilationStateImpl::~CompilationStateImpl() {
|
||||||
// {AbortCompilation} must have been called.
|
|
||||||
DCHECK(background_task_manager_.canceled());
|
DCHECK(background_task_manager_.canceled());
|
||||||
DCHECK(foreground_task_manager_.canceled());
|
DCHECK(foreground_task_manager_.canceled());
|
||||||
CompilationError* error = compile_error_.load(std::memory_order_acquire);
|
CompilationError* error = compile_error_.load(std::memory_order_acquire);
|
||||||
if (error != nullptr) delete error;
|
if (error != nullptr) delete error;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CompilationStateImpl::AbortCompilation() {
|
void CompilationStateImpl::CancelAndWait() {
|
||||||
background_task_manager_.CancelAndWait();
|
background_task_manager_.CancelAndWait();
|
||||||
foreground_task_manager_.CancelAndWait();
|
foreground_task_manager_.CancelAndWait();
|
||||||
}
|
}
|
||||||
@ -3023,10 +3182,26 @@ CompilationStateImpl::GetNextCompilationUnit() {
|
|||||||
return std::unique_ptr<WasmCompilationUnit>();
|
return std::unique_ptr<WasmCompilationUnit>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<WasmCompilationUnit>
|
||||||
|
CompilationStateImpl::GetNextExecutedUnit() {
|
||||||
|
std::vector<std::unique_ptr<WasmCompilationUnit>>& units = finish_units();
|
||||||
|
base::MutexGuard guard(&mutex_);
|
||||||
|
if (units.empty()) return {};
|
||||||
|
std::unique_ptr<WasmCompilationUnit> ret = std::move(units.back());
|
||||||
|
units.pop_back();
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CompilationStateImpl::HasCompilationUnitToFinish() {
|
||||||
|
return !finish_units().empty();
|
||||||
|
}
|
||||||
|
|
||||||
void CompilationStateImpl::OnFinishedUnit(ExecutionTier tier) {
|
void CompilationStateImpl::OnFinishedUnit(ExecutionTier tier) {
|
||||||
// This mutex guarantees that events happen in the right order.
|
// This mutex guarantees that events happen in the right order.
|
||||||
base::MutexGuard guard(&mutex_);
|
base::MutexGuard guard(&mutex_);
|
||||||
|
|
||||||
|
if (failed()) return;
|
||||||
|
|
||||||
// If we are *not* compiling in tiering mode, then all units are counted as
|
// If we are *not* compiling in tiering mode, then all units are counted as
|
||||||
// baseline units.
|
// baseline units.
|
||||||
bool is_tiering_mode = compile_mode_ == CompileMode::kTiering;
|
bool is_tiering_mode = compile_mode_ == CompileMode::kTiering;
|
||||||
@ -3136,8 +3311,19 @@ void CompilationStateImpl::RestartBackgroundTasks(size_t max) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CompilationStateImpl::SetFinisherIsRunning(bool value) {
|
||||||
|
base::MutexGuard guard(&mutex_);
|
||||||
|
if (finisher_is_running_ == value) return false;
|
||||||
|
finisher_is_running_ = value;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CompilationStateImpl::ScheduleFinisherTask() {
|
||||||
|
foreground_task_runner_->PostTask(
|
||||||
|
base::make_unique<FinishCompileTask>(this, &foreground_task_manager_));
|
||||||
|
}
|
||||||
|
|
||||||
void CompilationStateImpl::Abort() {
|
void CompilationStateImpl::Abort() {
|
||||||
printf("Abort: %p\n", this);
|
|
||||||
SetError(0, VoidResult::Error(0, "Compilation aborted"));
|
SetError(0, VoidResult::Error(0, "Compilation aborted"));
|
||||||
background_task_manager_.CancelAndWait();
|
background_task_manager_.CancelAndWait();
|
||||||
// No more callbacks after abort. Don't free the std::function objects here,
|
// No more callbacks after abort. Don't free the std::function objects here,
|
||||||
|
@ -65,11 +65,8 @@ Address CompileLazy(Isolate*, NativeModule*, uint32_t func_index);
|
|||||||
// allocates on the V8 heap (e.g. creating the module object) must be a
|
// allocates on the V8 heap (e.g. creating the module object) must be a
|
||||||
// foreground task. All other tasks (e.g. decoding and validating, the majority
|
// foreground task. All other tasks (e.g. decoding and validating, the majority
|
||||||
// of the work of compilation) can be background tasks.
|
// of the work of compilation) can be background tasks.
|
||||||
// AsyncCompileJobs are stored in shared_ptr by all tasks which need to keep
|
|
||||||
// them alive. {std::enable_shared_from_this} allows to regain a shared_ptr from
|
|
||||||
// a raw ptr.
|
|
||||||
// TODO(wasm): factor out common parts of this with the synchronous pipeline.
|
// TODO(wasm): factor out common parts of this with the synchronous pipeline.
|
||||||
class AsyncCompileJob : public std::enable_shared_from_this<AsyncCompileJob> {
|
class AsyncCompileJob {
|
||||||
public:
|
public:
|
||||||
AsyncCompileJob(Isolate* isolate, const WasmFeatures& enabled_features,
|
AsyncCompileJob(Isolate* isolate, const WasmFeatures& enabled_features,
|
||||||
std::unique_ptr<byte[]> bytes_copy, size_t length,
|
std::unique_ptr<byte[]> bytes_copy, size_t length,
|
||||||
@ -95,6 +92,7 @@ class AsyncCompileJob : public std::enable_shared_from_this<AsyncCompileJob> {
|
|||||||
class DecodeModule; // Step 1 (async)
|
class DecodeModule; // Step 1 (async)
|
||||||
class DecodeFail; // Step 1b (sync)
|
class DecodeFail; // Step 1b (sync)
|
||||||
class PrepareAndStartCompile; // Step 2 (sync)
|
class PrepareAndStartCompile; // Step 2 (sync)
|
||||||
|
class CompileFailed; // Step 4b (sync)
|
||||||
class CompileWrappers; // Step 5 (sync)
|
class CompileWrappers; // Step 5 (sync)
|
||||||
class FinishModule; // Step 6 (sync)
|
class FinishModule; // Step 6 (sync)
|
||||||
|
|
||||||
|
@ -103,10 +103,8 @@ void StreamingDecoder::Finish() {
|
|||||||
void StreamingDecoder::Abort() {
|
void StreamingDecoder::Abort() {
|
||||||
TRACE_STREAMING("Abort\n");
|
TRACE_STREAMING("Abort\n");
|
||||||
if (!ok()) return; // Failed already.
|
if (!ok()) return; // Failed already.
|
||||||
// Move the processor out of the unique_ptr field first, to avoid recursive
|
processor_->OnAbort();
|
||||||
// calls to {OnAbort}.
|
Fail();
|
||||||
std::unique_ptr<StreamingProcessor> processor = std::move(processor_);
|
|
||||||
processor->OnAbort();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void StreamingDecoder::SetModuleCompiledCallback(
|
void StreamingDecoder::SetModuleCompiledCallback(
|
||||||
|
@ -869,7 +869,7 @@ NativeModule::~NativeModule() {
|
|||||||
TRACE_HEAP("Deleting native module: %p\n", reinterpret_cast<void*>(this));
|
TRACE_HEAP("Deleting native module: %p\n", reinterpret_cast<void*>(this));
|
||||||
// Cancel all background compilation before resetting any field of the
|
// Cancel all background compilation before resetting any field of the
|
||||||
// NativeModule or freeing anything.
|
// NativeModule or freeing anything.
|
||||||
compilation_state_->AbortCompilation();
|
compilation_state_->CancelAndWait();
|
||||||
code_manager_->FreeNativeModule(this);
|
code_manager_->FreeNativeModule(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,7 +24,7 @@ WasmEngine::WasmEngine()
|
|||||||
|
|
||||||
WasmEngine::~WasmEngine() {
|
WasmEngine::~WasmEngine() {
|
||||||
// All AsyncCompileJobs have been canceled.
|
// All AsyncCompileJobs have been canceled.
|
||||||
DCHECK(async_compile_jobs_.empty());
|
DCHECK(jobs_.empty());
|
||||||
// All Isolates have been deregistered.
|
// All Isolates have been deregistered.
|
||||||
DCHECK(isolates_.empty());
|
DCHECK(isolates_.empty());
|
||||||
}
|
}
|
||||||
@ -212,7 +212,7 @@ void WasmEngine::AsyncCompile(
|
|||||||
std::unique_ptr<byte[]> copy(new byte[bytes.length()]);
|
std::unique_ptr<byte[]> copy(new byte[bytes.length()]);
|
||||||
memcpy(copy.get(), bytes.start(), bytes.length());
|
memcpy(copy.get(), bytes.start(), bytes.length());
|
||||||
|
|
||||||
std::shared_ptr<AsyncCompileJob> job = CreateAsyncCompileJob(
|
AsyncCompileJob* job = CreateAsyncCompileJob(
|
||||||
isolate, enabled, std::move(copy), bytes.length(),
|
isolate, enabled, std::move(copy), bytes.length(),
|
||||||
handle(isolate->context(), isolate), std::move(resolver));
|
handle(isolate->context(), isolate), std::move(resolver));
|
||||||
job->Start();
|
job->Start();
|
||||||
@ -221,7 +221,7 @@ void WasmEngine::AsyncCompile(
|
|||||||
std::shared_ptr<StreamingDecoder> WasmEngine::StartStreamingCompilation(
|
std::shared_ptr<StreamingDecoder> WasmEngine::StartStreamingCompilation(
|
||||||
Isolate* isolate, const WasmFeatures& enabled, Handle<Context> context,
|
Isolate* isolate, const WasmFeatures& enabled, Handle<Context> context,
|
||||||
std::shared_ptr<CompilationResultResolver> resolver) {
|
std::shared_ptr<CompilationResultResolver> resolver) {
|
||||||
std::shared_ptr<AsyncCompileJob> job =
|
AsyncCompileJob* job =
|
||||||
CreateAsyncCompileJob(isolate, enabled, std::unique_ptr<byte[]>(nullptr),
|
CreateAsyncCompileJob(isolate, enabled, std::unique_ptr<byte[]>(nullptr),
|
||||||
0, context, std::move(resolver));
|
0, context, std::move(resolver));
|
||||||
return job->CreateStreamingDecoder();
|
return job->CreateStreamingDecoder();
|
||||||
@ -278,49 +278,48 @@ CodeTracer* WasmEngine::GetCodeTracer() {
|
|||||||
return code_tracer_.get();
|
return code_tracer_.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<AsyncCompileJob> WasmEngine::CreateAsyncCompileJob(
|
AsyncCompileJob* WasmEngine::CreateAsyncCompileJob(
|
||||||
Isolate* isolate, const WasmFeatures& enabled,
|
Isolate* isolate, const WasmFeatures& enabled,
|
||||||
std::unique_ptr<byte[]> bytes_copy, size_t length, Handle<Context> context,
|
std::unique_ptr<byte[]> bytes_copy, size_t length, Handle<Context> context,
|
||||||
std::shared_ptr<CompilationResultResolver> resolver) {
|
std::shared_ptr<CompilationResultResolver> resolver) {
|
||||||
std::shared_ptr<AsyncCompileJob> job =
|
AsyncCompileJob* job =
|
||||||
std::make_shared<AsyncCompileJob>(isolate, enabled, std::move(bytes_copy),
|
new AsyncCompileJob(isolate, enabled, std::move(bytes_copy), length,
|
||||||
length, context, std::move(resolver));
|
context, std::move(resolver));
|
||||||
|
// Pass ownership to the unique_ptr in {jobs_}.
|
||||||
base::MutexGuard guard(&mutex_);
|
base::MutexGuard guard(&mutex_);
|
||||||
async_compile_jobs_.insert({job.get(), job});
|
jobs_[job] = std::unique_ptr<AsyncCompileJob>(job);
|
||||||
return job;
|
return job;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WasmEngine::RemoveCompileJob(AsyncCompileJob* job) {
|
std::unique_ptr<AsyncCompileJob> WasmEngine::RemoveCompileJob(
|
||||||
|
AsyncCompileJob* job) {
|
||||||
base::MutexGuard guard(&mutex_);
|
base::MutexGuard guard(&mutex_);
|
||||||
auto item = async_compile_jobs_.find(job);
|
auto item = jobs_.find(job);
|
||||||
DCHECK(item != async_compile_jobs_.end());
|
DCHECK(item != jobs_.end());
|
||||||
async_compile_jobs_.erase(item);
|
std::unique_ptr<AsyncCompileJob> result = std::move(item->second);
|
||||||
|
jobs_.erase(item);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool WasmEngine::HasRunningCompileJob(Isolate* isolate) {
|
bool WasmEngine::HasRunningCompileJob(Isolate* isolate) {
|
||||||
base::MutexGuard guard(&mutex_);
|
base::MutexGuard guard(&mutex_);
|
||||||
DCHECK_EQ(1, isolates_.count(isolate));
|
DCHECK_EQ(1, isolates_.count(isolate));
|
||||||
for (auto& entry : async_compile_jobs_) {
|
for (auto& entry : jobs_) {
|
||||||
if (entry.first->isolate() == isolate) return true;
|
if (entry.first->isolate() == isolate) return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void WasmEngine::AbortCompileJobsOnIsolate(Isolate* isolate) {
|
void WasmEngine::DeleteCompileJobsOnIsolate(Isolate* isolate) {
|
||||||
// Copy out to a vector first, since abortion can free {AsyncCompileJob}s and
|
base::MutexGuard guard(&mutex_);
|
||||||
// thus modify the {async_compile_jobs_} set.
|
DCHECK_EQ(1, isolates_.count(isolate));
|
||||||
std::vector<std::shared_ptr<AsyncCompileJob>> compile_jobs_to_abort;
|
for (auto it = jobs_.begin(); it != jobs_.end();) {
|
||||||
{
|
if (it->first->isolate() == isolate) {
|
||||||
base::MutexGuard guard(&mutex_);
|
it = jobs_.erase(it);
|
||||||
DCHECK_EQ(1, isolates_.count(isolate));
|
} else {
|
||||||
for (auto& job_entry : async_compile_jobs_) {
|
++it;
|
||||||
if (job_entry.first->isolate() != isolate) continue;
|
|
||||||
if (auto shared_job = job_entry.second.lock()) {
|
|
||||||
compile_jobs_to_abort.emplace_back(std::move(shared_job));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (auto job : compile_jobs_to_abort) job->Abort();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WasmEngine::AddIsolate(Isolate* isolate) {
|
void WasmEngine::AddIsolate(Isolate* isolate) {
|
||||||
|
@ -131,16 +131,16 @@ class V8_EXPORT_PRIVATE WasmEngine {
|
|||||||
CodeTracer* GetCodeTracer();
|
CodeTracer* GetCodeTracer();
|
||||||
|
|
||||||
// Remove {job} from the list of active compile jobs.
|
// Remove {job} from the list of active compile jobs.
|
||||||
void RemoveCompileJob(AsyncCompileJob* job);
|
std::unique_ptr<AsyncCompileJob> RemoveCompileJob(AsyncCompileJob* job);
|
||||||
|
|
||||||
// Returns true if at least one AsyncCompileJob that belongs to the given
|
// Returns true if at least one AsyncCompileJob that belongs to the given
|
||||||
// Isolate is currently running.
|
// Isolate is currently running.
|
||||||
bool HasRunningCompileJob(Isolate* isolate);
|
bool HasRunningCompileJob(Isolate* isolate);
|
||||||
|
|
||||||
// Aborts all AsyncCompileJobs that belong to the given Isolate. All
|
// Deletes all AsyncCompileJobs that belong to the given Isolate. All
|
||||||
// compilation is aborted, no more callbacks will be triggered. This is used
|
// compilation is aborted, no more callbacks will be triggered. This is used
|
||||||
// for tearing down an isolate, or to clean it up to be reused.
|
// for tearing down an isolate, or to clean it up to be reused.
|
||||||
void AbortCompileJobsOnIsolate(Isolate* isolate);
|
void DeleteCompileJobsOnIsolate(Isolate* isolate);
|
||||||
|
|
||||||
// Manage the set of Isolates that use this WasmEngine.
|
// Manage the set of Isolates that use this WasmEngine.
|
||||||
void AddIsolate(Isolate* isolate);
|
void AddIsolate(Isolate* isolate);
|
||||||
@ -155,7 +155,7 @@ class V8_EXPORT_PRIVATE WasmEngine {
|
|||||||
static std::shared_ptr<WasmEngine> GetWasmEngine();
|
static std::shared_ptr<WasmEngine> GetWasmEngine();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::shared_ptr<AsyncCompileJob> CreateAsyncCompileJob(
|
AsyncCompileJob* CreateAsyncCompileJob(
|
||||||
Isolate* isolate, const WasmFeatures& enabled,
|
Isolate* isolate, const WasmFeatures& enabled,
|
||||||
std::unique_ptr<byte[]> bytes_copy, size_t length,
|
std::unique_ptr<byte[]> bytes_copy, size_t length,
|
||||||
Handle<Context> context,
|
Handle<Context> context,
|
||||||
@ -172,11 +172,9 @@ class V8_EXPORT_PRIVATE WasmEngine {
|
|||||||
//////////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////////
|
||||||
// Protected by {mutex_}:
|
// Protected by {mutex_}:
|
||||||
|
|
||||||
// Keep weak_ptrs to the AsyncCompileJob so we can detect the intermediate
|
// We use an AsyncCompileJob as the key for itself so that we can delete the
|
||||||
// state where the refcount already dropped to zero (and the weak_ptr is
|
// job from the map when it is finished.
|
||||||
// cleared) but the destructor did not run to completion yet.
|
std::unordered_map<AsyncCompileJob*, std::unique_ptr<AsyncCompileJob>> jobs_;
|
||||||
std::unordered_map<AsyncCompileJob*, std::weak_ptr<AsyncCompileJob>>
|
|
||||||
async_compile_jobs_;
|
|
||||||
|
|
||||||
std::unique_ptr<CompilationStatistics> compilation_stats_;
|
std::unique_ptr<CompilationStatistics> compilation_stats_;
|
||||||
std::unique_ptr<CodeTracer> code_tracer_;
|
std::unique_ptr<CodeTracer> code_tracer_;
|
||||||
|
Loading…
Reference in New Issue
Block a user