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(
InProcessStackDumping::kDisabled,
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.
*
......
......@@ -1913,6 +1913,7 @@ DEFINE_NEG_IMPLICATION(single_threaded_gc, concurrent_store_buffer)
DEFINE_NEG_IMPLICATION(single_threaded_gc, minor_mc_parallel_marking)
#endif // ENABLE_MINOR_MC
DEFINE_NEG_IMPLICATION(single_threaded_gc, concurrent_array_buffer_sweeping)
DEFINE_NEG_IMPLICATION(single_threaded_gc, stress_concurrent_allocation)
#undef FLAG
......
......@@ -30,6 +30,16 @@ void PrintStackTrace() {
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
std::unique_ptr<v8::Platform> NewDefaultPlatform(
......@@ -39,9 +49,21 @@ std::unique_ptr<v8::Platform> NewDefaultPlatform(
if (in_process_stack_dumping == InProcessStackDumping::kEnabled) {
v8::base::debug::EnableInProcessStackDumping();
}
thread_pool_size = GetActualThreadPoolSize(thread_pool_size);
auto platform = std::make_unique<DefaultPlatform>(
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;
}
......@@ -75,22 +97,10 @@ void NotifyIsolateShutdown(v8::Platform* platform, Isolate* 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(
int thread_pool_size, IdleTaskSupport idle_task_support,
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),
tracing_controller_(std::move(tracing_controller)),
page_allocator_(std::make_unique<v8::base::PageAllocator>()) {
......@@ -101,6 +111,9 @@ DefaultPlatform::DefaultPlatform(
#endif
tracing_controller_.reset(controller);
}
if (thread_pool_size_ > 0) {
EnsureBackgroundTaskRunnerInitialized();
}
}
DefaultPlatform::~DefaultPlatform() {
......@@ -121,14 +134,13 @@ double DefaultTimeFunction() {
} // namespace
void DefaultPlatform::EnsureBackgroundTaskRunnerInitialized() {
base::MutexGuard guard(&lock_);
if (!worker_threads_task_runner_) {
worker_threads_task_runner_ =
std::make_shared<DefaultWorkerThreadsTaskRunner>(
thread_pool_size_, time_function_for_testing_
? time_function_for_testing_
: DefaultTimeFunction);
}
DCHECK_NULL(worker_threads_task_runner_);
worker_threads_task_runner_ =
std::make_shared<DefaultWorkerThreadsTaskRunner>(
thread_pool_size_, time_function_for_testing_
? time_function_for_testing_
: DefaultTimeFunction);
DCHECK_NOT_NULL(worker_threads_task_runner_);
}
void DefaultPlatform::SetTimeFunctionForTesting(
......@@ -196,13 +208,23 @@ std::shared_ptr<TaskRunner> DefaultPlatform::GetForegroundTaskRunner(
}
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));
}
void DefaultPlatform::CallDelayedOnWorkerThread(std::unique_ptr<Task> task,
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),
delay_in_seconds);
}
......
......@@ -28804,3 +28804,35 @@ TEST(CodeLikeFunction) {
CHECK(CompileRun("new Function(new Other())()").IsEmpty());
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 = {
"no_wasm_traps": ["--wasm-trap-handler"],
"nooptimization": ["--opt", "--no-liftoff", "--predictable", "--wasm-tier-up"],
"slow_path": ["--no-force-slow-path"],
"stress_concurrent_allocation": ["--single-threaded-gc", "--predictable"],
"stress_incremental_marking": ["--no-stress-incremental-marking"],
"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=*",
......@@ -77,7 +78,8 @@ INCOMPATIBLE_FLAGS_PER_BUILD_VARIABLE = {
+ INCOMPATIBLE_FLAGS_PER_VARIANT["jitless"],
"predictable": ["--liftoff", "--parallel-compile-tasks",
"--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.
......@@ -92,6 +94,7 @@ INCOMPATIBLE_FLAGS_PER_EXTRA_FLAG = {
"--no-enable-sse3": ["--enable-sse3"],
"--no-enable-sse4-1": ["--enable-sse4-1"],
"--optimize-for-size": ["--max-semi-space-size=*"],
"--stress_concurrent_allocation": ["--single-threaded-gc", "--predictable"],
"--stress-flush-bytecode": ["--no-stress-flush-bytecode"],
"--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