Commit a18a674b authored by Ulan Degenbaev's avatar Ulan Degenbaev Committed by Commit Bot

[api] Introduce a single-threaded version of DefaultPlatform

The new platform can be used in combination with --single-threaded.
It disables background threads and thus avoids waiting on mutexes
and condition variables completely, which is useful for V8 embedders
that fork the V8 process after initialization.

As a bonus the new platform allows use to test --single-threaded and
has already uncovered an existing bug in parallel pointer updating code.

Change-Id: I3446fa027d2a077641cdaac0cd08062a1acae176
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2416501
Commit-Queue: Ulan Degenbaev <ulan@chromium.org>
Reviewed-by: 's avatarMichael Lippautz <mlippautz@chromium.org>
Cr-Commit-Position: refs/heads/master@{#71187}
parent 466166b8
...@@ -43,6 +43,17 @@ V8_PLATFORM_EXPORT std::unique_ptr<v8::Platform> NewDefaultPlatform( ...@@ -43,6 +43,17 @@ V8_PLATFORM_EXPORT std::unique_ptr<v8::Platform> NewDefaultPlatform(
InProcessStackDumping::kDisabled, InProcessStackDumping::kDisabled,
std::unique_ptr<v8::TracingController> tracing_controller = {}); std::unique_ptr<v8::TracingController> tracing_controller = {});
/**
* The same as NewDefaultPlatform but disables the worker thread pool.
* It must be used with the --single-threaded V8 flag.
*/
V8_PLATFORM_EXPORT std::unique_ptr<v8::Platform>
NewSingleThreadedDefaultPlatform(
IdleTaskSupport idle_task_support = IdleTaskSupport::kDisabled,
InProcessStackDumping in_process_stack_dumping =
InProcessStackDumping::kDisabled,
std::unique_ptr<v8::TracingController> tracing_controller = {});
/** /**
* Returns a new instance of the default v8::JobHandle implementation. * Returns a new instance of the default v8::JobHandle implementation.
* *
......
...@@ -1913,6 +1913,7 @@ DEFINE_NEG_IMPLICATION(single_threaded_gc, concurrent_store_buffer) ...@@ -1913,6 +1913,7 @@ DEFINE_NEG_IMPLICATION(single_threaded_gc, concurrent_store_buffer)
DEFINE_NEG_IMPLICATION(single_threaded_gc, minor_mc_parallel_marking) DEFINE_NEG_IMPLICATION(single_threaded_gc, minor_mc_parallel_marking)
#endif // ENABLE_MINOR_MC #endif // ENABLE_MINOR_MC
DEFINE_NEG_IMPLICATION(single_threaded_gc, concurrent_array_buffer_sweeping) DEFINE_NEG_IMPLICATION(single_threaded_gc, concurrent_array_buffer_sweeping)
DEFINE_NEG_IMPLICATION(single_threaded_gc, stress_concurrent_allocation)
#undef FLAG #undef FLAG
......
...@@ -30,6 +30,16 @@ void PrintStackTrace() { ...@@ -30,6 +30,16 @@ void PrintStackTrace() {
v8::base::debug::DisableSignalStackDump(); v8::base::debug::DisableSignalStackDump();
} }
constexpr int kMaxThreadPoolSize = 16;
int GetActualThreadPoolSize(int thread_pool_size) {
DCHECK_GE(thread_pool_size, 0);
if (thread_pool_size < 1) {
thread_pool_size = base::SysInfo::NumberOfProcessors() - 1;
}
return std::max(std::min(thread_pool_size, kMaxThreadPoolSize), 1);
}
} // namespace } // namespace
std::unique_ptr<v8::Platform> NewDefaultPlatform( std::unique_ptr<v8::Platform> NewDefaultPlatform(
...@@ -39,9 +49,21 @@ std::unique_ptr<v8::Platform> NewDefaultPlatform( ...@@ -39,9 +49,21 @@ std::unique_ptr<v8::Platform> NewDefaultPlatform(
if (in_process_stack_dumping == InProcessStackDumping::kEnabled) { if (in_process_stack_dumping == InProcessStackDumping::kEnabled) {
v8::base::debug::EnableInProcessStackDumping(); v8::base::debug::EnableInProcessStackDumping();
} }
thread_pool_size = GetActualThreadPoolSize(thread_pool_size);
auto platform = std::make_unique<DefaultPlatform>( auto platform = std::make_unique<DefaultPlatform>(
thread_pool_size, idle_task_support, std::move(tracing_controller)); thread_pool_size, idle_task_support, std::move(tracing_controller));
platform->EnsureBackgroundTaskRunnerInitialized(); return platform;
}
std::unique_ptr<v8::Platform> NewSingleThreadedDefaultPlatform(
IdleTaskSupport idle_task_support,
InProcessStackDumping in_process_stack_dumping,
std::unique_ptr<v8::TracingController> tracing_controller) {
if (in_process_stack_dumping == InProcessStackDumping::kEnabled) {
v8::base::debug::EnableInProcessStackDumping();
}
auto platform = std::make_unique<DefaultPlatform>(
0, idle_task_support, std::move(tracing_controller));
return platform; return platform;
} }
...@@ -75,22 +97,10 @@ void NotifyIsolateShutdown(v8::Platform* platform, Isolate* isolate) { ...@@ -75,22 +97,10 @@ void NotifyIsolateShutdown(v8::Platform* platform, Isolate* isolate) {
static_cast<DefaultPlatform*>(platform)->NotifyIsolateShutdown(isolate); static_cast<DefaultPlatform*>(platform)->NotifyIsolateShutdown(isolate);
} }
namespace {
constexpr int kMaxThreadPoolSize = 16;
int GetActualThreadPoolSize(int thread_pool_size) {
DCHECK_GE(thread_pool_size, 0);
if (thread_pool_size < 1) {
thread_pool_size = base::SysInfo::NumberOfProcessors() - 1;
}
return std::max(std::min(thread_pool_size, kMaxThreadPoolSize), 1);
}
} // namespace
DefaultPlatform::DefaultPlatform( DefaultPlatform::DefaultPlatform(
int thread_pool_size, IdleTaskSupport idle_task_support, int thread_pool_size, IdleTaskSupport idle_task_support,
std::unique_ptr<v8::TracingController> tracing_controller) std::unique_ptr<v8::TracingController> tracing_controller)
: thread_pool_size_(GetActualThreadPoolSize(thread_pool_size)), : thread_pool_size_(thread_pool_size),
idle_task_support_(idle_task_support), idle_task_support_(idle_task_support),
tracing_controller_(std::move(tracing_controller)), tracing_controller_(std::move(tracing_controller)),
page_allocator_(std::make_unique<v8::base::PageAllocator>()) { page_allocator_(std::make_unique<v8::base::PageAllocator>()) {
...@@ -101,6 +111,9 @@ DefaultPlatform::DefaultPlatform( ...@@ -101,6 +111,9 @@ DefaultPlatform::DefaultPlatform(
#endif #endif
tracing_controller_.reset(controller); tracing_controller_.reset(controller);
} }
if (thread_pool_size_ > 0) {
EnsureBackgroundTaskRunnerInitialized();
}
} }
DefaultPlatform::~DefaultPlatform() { DefaultPlatform::~DefaultPlatform() {
...@@ -121,14 +134,13 @@ double DefaultTimeFunction() { ...@@ -121,14 +134,13 @@ double DefaultTimeFunction() {
} // namespace } // namespace
void DefaultPlatform::EnsureBackgroundTaskRunnerInitialized() { void DefaultPlatform::EnsureBackgroundTaskRunnerInitialized() {
base::MutexGuard guard(&lock_); DCHECK_NULL(worker_threads_task_runner_);
if (!worker_threads_task_runner_) { worker_threads_task_runner_ =
worker_threads_task_runner_ = std::make_shared<DefaultWorkerThreadsTaskRunner>(
std::make_shared<DefaultWorkerThreadsTaskRunner>( thread_pool_size_, time_function_for_testing_
thread_pool_size_, time_function_for_testing_ ? time_function_for_testing_
? time_function_for_testing_ : DefaultTimeFunction);
: DefaultTimeFunction); DCHECK_NOT_NULL(worker_threads_task_runner_);
}
} }
void DefaultPlatform::SetTimeFunctionForTesting( void DefaultPlatform::SetTimeFunctionForTesting(
...@@ -196,13 +208,23 @@ std::shared_ptr<TaskRunner> DefaultPlatform::GetForegroundTaskRunner( ...@@ -196,13 +208,23 @@ std::shared_ptr<TaskRunner> DefaultPlatform::GetForegroundTaskRunner(
} }
void DefaultPlatform::CallOnWorkerThread(std::unique_ptr<Task> task) { void DefaultPlatform::CallOnWorkerThread(std::unique_ptr<Task> task) {
EnsureBackgroundTaskRunnerInitialized(); // If this DCHECK fires, then this means that either
// - V8 is running without the --single-threaded flag but
// but the platform was created as a single-threaded platform.
// - or some component in V8 is ignoring --single-threaded
// and posting a background task.
DCHECK_NOT_NULL(worker_threads_task_runner_);
worker_threads_task_runner_->PostTask(std::move(task)); worker_threads_task_runner_->PostTask(std::move(task));
} }
void DefaultPlatform::CallDelayedOnWorkerThread(std::unique_ptr<Task> task, void DefaultPlatform::CallDelayedOnWorkerThread(std::unique_ptr<Task> task,
double delay_in_seconds) { double delay_in_seconds) {
EnsureBackgroundTaskRunnerInitialized(); // If this DCHECK fires, then this means that either
// - V8 is running without the --single-threaded flag but
// but the platform was created as a single-threaded platform.
// - or some component in V8 is ignoring --single-threaded
// and posting a background task.
DCHECK_NOT_NULL(worker_threads_task_runner_);
worker_threads_task_runner_->PostDelayedTask(std::move(task), worker_threads_task_runner_->PostDelayedTask(std::move(task),
delay_in_seconds); delay_in_seconds);
} }
......
...@@ -28804,3 +28804,35 @@ TEST(CodeLikeFunction) { ...@@ -28804,3 +28804,35 @@ TEST(CodeLikeFunction) {
CHECK(CompileRun("new Function(new Other())()").IsEmpty()); CHECK(CompileRun("new Function(new Other())()").IsEmpty());
ExpectInt32("new Function(new CodeLike())()", 7); ExpectInt32("new Function(new CodeLike())()", 7);
} }
UNINITIALIZED_TEST(SingleThreadedDefaultPlatform) {
v8::V8::SetFlagsFromString("--single-threaded");
auto old_platform = i::V8::GetCurrentPlatform();
std::unique_ptr<v8::Platform> new_platform(
v8::platform::NewSingleThreadedDefaultPlatform());
i::V8::SetPlatformForTesting(new_platform.get());
v8::Isolate::CreateParams create_params;
create_params.array_buffer_allocator = CcTest::array_buffer_allocator();
v8::Isolate* isolate = v8::Isolate::New(create_params);
isolate->Enter();
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
{
i::HandleScope scope(i_isolate);
v8::Local<Context> env = Context::New(isolate);
env->Enter();
CompileRunChecked(isolate,
"function f() {"
" for (let i = 0; i < 10; i++)"
" (new Array(10)).fill(0);"
" return 0;"
"}"
"f();");
env->Exit();
}
CcTest::CollectGarbage(i::NEW_SPACE, i_isolate);
CcTest::CollectAllAvailableGarbage(i_isolate);
isolate->Exit();
isolate->Dispose();
i::V8::SetPlatformForTesting(old_platform);
}
...@@ -57,6 +57,7 @@ INCOMPATIBLE_FLAGS_PER_VARIANT = { ...@@ -57,6 +57,7 @@ INCOMPATIBLE_FLAGS_PER_VARIANT = {
"no_wasm_traps": ["--wasm-trap-handler"], "no_wasm_traps": ["--wasm-trap-handler"],
"nooptimization": ["--opt", "--no-liftoff", "--predictable", "--wasm-tier-up"], "nooptimization": ["--opt", "--no-liftoff", "--predictable", "--wasm-tier-up"],
"slow_path": ["--no-force-slow-path"], "slow_path": ["--no-force-slow-path"],
"stress_concurrent_allocation": ["--single-threaded-gc", "--predictable"],
"stress_incremental_marking": ["--no-stress-incremental-marking"], "stress_incremental_marking": ["--no-stress-incremental-marking"],
"stress_js_bg_compile_wasm_code_gc": ["--no-stress-background-compile"], "stress_js_bg_compile_wasm_code_gc": ["--no-stress-background-compile"],
"stress": ["--no-stress-opt", "--always-opt", "--no-always-opt", "--liftoff", "--max-inlined-bytecode-size=*", "stress": ["--no-stress-opt", "--always-opt", "--no-always-opt", "--liftoff", "--max-inlined-bytecode-size=*",
...@@ -77,7 +78,8 @@ INCOMPATIBLE_FLAGS_PER_BUILD_VARIABLE = { ...@@ -77,7 +78,8 @@ INCOMPATIBLE_FLAGS_PER_BUILD_VARIABLE = {
+ INCOMPATIBLE_FLAGS_PER_VARIANT["jitless"], + INCOMPATIBLE_FLAGS_PER_VARIANT["jitless"],
"predictable": ["--liftoff", "--parallel-compile-tasks", "predictable": ["--liftoff", "--parallel-compile-tasks",
"--concurrent-recompilation", "--concurrent-recompilation",
"--wasm-num-compilation-tasks=*"], "--wasm-num-compilation-tasks=*",
"--stress-concurrent-allocation"],
} }
# Flags that lead to a contradiction when a certain extra-flag is present. # Flags that lead to a contradiction when a certain extra-flag is present.
...@@ -92,6 +94,7 @@ INCOMPATIBLE_FLAGS_PER_EXTRA_FLAG = { ...@@ -92,6 +94,7 @@ INCOMPATIBLE_FLAGS_PER_EXTRA_FLAG = {
"--no-enable-sse3": ["--enable-sse3"], "--no-enable-sse3": ["--enable-sse3"],
"--no-enable-sse4-1": ["--enable-sse4-1"], "--no-enable-sse4-1": ["--enable-sse4-1"],
"--optimize-for-size": ["--max-semi-space-size=*"], "--optimize-for-size": ["--max-semi-space-size=*"],
"--stress_concurrent_allocation": ["--single-threaded-gc", "--predictable"],
"--stress-flush-bytecode": ["--no-stress-flush-bytecode"], "--stress-flush-bytecode": ["--no-stress-flush-bytecode"],
"--stress-incremental-marking": INCOMPATIBLE_FLAGS_PER_VARIANT["stress_incremental_marking"], "--stress-incremental-marking": INCOMPATIBLE_FLAGS_PER_VARIANT["stress_incremental_marking"],
} }
......
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