summaryrefslogtreecommitdiff
path: root/chromium/v8/src/d8
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2020-10-29 10:46:47 +0100
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2020-11-02 12:02:10 +0000
commit99677208ff3b216fdfec551fbe548da5520cd6fb (patch)
tree476a4865c10320249360e859d8fdd3e01833b03a /chromium/v8/src/d8
parentc30a6232df03e1efbd9f3b226777b07e087a1122 (diff)
downloadqtwebengine-chromium-99677208ff3b216fdfec551fbe548da5520cd6fb.tar.gz
BASELINE: Update Chromium to 86.0.4240.124
Change-Id: Ide0ff151e94cd665ae6521a446995d34a9d1d644 Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/v8/src/d8')
-rw-r--r--chromium/v8/src/d8/async-hooks-wrapper.cc1
-rw-r--r--chromium/v8/src/d8/cov.cc58
-rw-r--r--chromium/v8/src/d8/cov.h7
-rw-r--r--chromium/v8/src/d8/d8-platforms.cc52
-rw-r--r--chromium/v8/src/d8/d8.cc337
-rw-r--r--chromium/v8/src/d8/d8.h48
6 files changed, 392 insertions, 111 deletions
diff --git a/chromium/v8/src/d8/async-hooks-wrapper.cc b/chromium/v8/src/d8/async-hooks-wrapper.cc
index f96aad41233..1d160cdb0da 100644
--- a/chromium/v8/src/d8/async-hooks-wrapper.cc
+++ b/chromium/v8/src/d8/async-hooks-wrapper.cc
@@ -128,6 +128,7 @@ void AsyncHooks::ShellPromiseHook(PromiseHookType type, Local<Promise> promise,
HandleScope handle_scope(hooks->isolate_);
Local<Context> currentContext = hooks->isolate_->GetCurrentContext();
+ DCHECK(!currentContext.IsEmpty());
if (type == PromiseHookType::kInit) {
++hooks->current_async_id;
diff --git a/chromium/v8/src/d8/cov.cc b/chromium/v8/src/d8/cov.cc
index 47e2af599c0..d95134a9958 100644
--- a/chromium/v8/src/d8/cov.cc
+++ b/chromium/v8/src/d8/cov.cc
@@ -24,10 +24,13 @@ struct shmem_data {
struct shmem_data* shmem;
-uint32_t *__edges_start, *__edges_stop;
-void __sanitizer_cov_reset_edgeguards() {
+uint32_t *edges_start, *edges_stop;
+uint32_t builtins_start;
+uint32_t builtins_edge_count;
+
+void sanitizer_cov_reset_edgeguards() {
uint32_t N = 0;
- for (uint32_t* x = __edges_start; x < __edges_stop && N < MAX_EDGES; x++)
+ for (uint32_t* x = edges_start; x < edges_stop && N < MAX_EDGES; x++)
*x = ++N;
}
@@ -53,15 +56,27 @@ extern "C" void __sanitizer_cov_trace_pc_guard_init(uint32_t* start,
}
}
- __edges_start = start;
- __edges_stop = stop;
- __sanitizer_cov_reset_edgeguards();
+ edges_start = start;
+ edges_stop = stop;
+ sanitizer_cov_reset_edgeguards();
shmem->num_edges = static_cast<uint32_t>(stop - start);
+ builtins_start = 1 + shmem->num_edges;
printf("[COV] edge counters initialized. Shared memory: %s with %u edges\n",
shm_key, shmem->num_edges);
}
+uint32_t sanitizer_cov_count_discovered_edges() {
+ uint32_t on_edges_counter = 0;
+ for (uint32_t i = 1; i < builtins_start; ++i) {
+ // TODO(ralbovsky): Can be optimized for fewer divisions.
+ if (shmem->edges[i / 8] & (1 << (i % 8))) {
+ ++on_edges_counter;
+ }
+ }
+ return on_edges_counter;
+}
+
extern "C" void __sanitizer_cov_trace_pc_guard(uint32_t* guard) {
// There's a small race condition here: if this function executes in two
// threads for the same edge at the same time, the first thread might disable
@@ -72,3 +87,34 @@ extern "C" void __sanitizer_cov_trace_pc_guard(uint32_t* guard) {
shmem->edges[index / 8] |= 1 << (index % 8);
*guard = 0;
}
+
+void cov_init_builtins_edges(uint32_t num_edges) {
+ if (num_edges + shmem->num_edges > MAX_EDGES) {
+ printf(
+ "[COV] Error: Insufficient amount of edges left for builtins "
+ "coverage.\n");
+ exit(-1);
+ }
+ builtins_edge_count = num_edges;
+ builtins_start = 1 + shmem->num_edges;
+ shmem->num_edges += builtins_edge_count;
+ printf("[COV] Additional %d edges for builtins initialized.\n", num_edges);
+}
+
+// This function is ran once per REPRL loop. In case of crash the coverage of
+// crash will not be stored in shared memory. Therefore, it would be useful, if
+// we could store these coverage information into shared memory in real time.
+void cov_update_builtins_basic_block_coverage(
+ const std::vector<bool>& cov_map) {
+ if (cov_map.size() != builtins_edge_count) {
+ printf("[COV] Error: Size of builtins cov map changed.\n");
+ exit(-1);
+ }
+ for (uint32_t i = 0; i < cov_map.size(); ++i) {
+ if (cov_map[i]) {
+ // TODO(ralbovsky): Can be optimized for fewer divisions.
+ shmem->edges[(i + builtins_start) / 8] |=
+ (1 << ((i + builtins_start) % 8));
+ }
+ }
+}
diff --git a/chromium/v8/src/d8/cov.h b/chromium/v8/src/d8/cov.h
index d2d26752337..0c7dc6bac42 100644
--- a/chromium/v8/src/d8/cov.h
+++ b/chromium/v8/src/d8/cov.h
@@ -10,6 +10,11 @@
// memory
// https://clang.llvm.org/docs/SanitizerCoverage.html
-void __sanitizer_cov_reset_edgeguards();
+#include <vector>
+
+void sanitizer_cov_reset_edgeguards();
+uint32_t sanitizer_cov_count_discovered_edges();
+void cov_init_builtins_edges(uint32_t num_edges);
+void cov_update_builtins_basic_block_coverage(const std::vector<bool>& cov_map);
#endif // V8_D8_COV_H_
diff --git a/chromium/v8/src/d8/d8-platforms.cc b/chromium/v8/src/d8/d8-platforms.cc
index 8f528e2d43c..a170e39c923 100644
--- a/chromium/v8/src/d8/d8-platforms.cc
+++ b/chromium/v8/src/d8/d8-platforms.cc
@@ -16,7 +16,7 @@
namespace v8 {
-class PredictablePlatform : public Platform {
+class PredictablePlatform final : public Platform {
public:
explicit PredictablePlatform(std::unique_ptr<Platform> platform)
: platform_(std::move(platform)) {
@@ -63,6 +63,11 @@ class PredictablePlatform : public Platform {
bool IdleTasksEnabled(Isolate* isolate) override { return false; }
+ std::unique_ptr<JobHandle> PostJob(
+ TaskPriority priority, std::unique_ptr<JobTask> job_task) override {
+ return platform_->PostJob(priority, std::move(job_task));
+ }
+
double MonotonicallyIncreasingTime() override {
return synthetic_time_in_sec_ += 0.00001;
}
@@ -89,7 +94,7 @@ std::unique_ptr<Platform> MakePredictablePlatform(
return std::make_unique<PredictablePlatform>(std::move(platform));
}
-class DelayedTasksPlatform : public Platform {
+class DelayedTasksPlatform final : public Platform {
public:
explicit DelayedTasksPlatform(std::unique_ptr<Platform> platform)
: platform_(std::move(platform)) {
@@ -159,6 +164,11 @@ class DelayedTasksPlatform : public Platform {
return platform_->IdleTasksEnabled(isolate);
}
+ std::unique_ptr<JobHandle> PostJob(
+ TaskPriority priority, std::unique_ptr<JobTask> job_task) override {
+ return platform_->PostJob(priority, MakeDelayedJob(std::move(job_task)));
+ }
+
double MonotonicallyIncreasingTime() override {
return platform_->MonotonicallyIncreasingTime();
}
@@ -222,11 +232,12 @@ class DelayedTasksPlatform : public Platform {
}
};
- class DelayedTask : public Task {
+ class DelayedTask final : public Task {
public:
DelayedTask(std::unique_ptr<Task> task, int32_t delay_ms)
: task_(std::move(task)), delay_ms_(delay_ms) {}
- void Run() final {
+
+ void Run() override {
base::OS::Sleep(base::TimeDelta::FromMicroseconds(delay_ms_));
task_->Run();
}
@@ -236,11 +247,12 @@ class DelayedTasksPlatform : public Platform {
int32_t delay_ms_;
};
- class DelayedIdleTask : public IdleTask {
+ class DelayedIdleTask final : public IdleTask {
public:
DelayedIdleTask(std::unique_ptr<IdleTask> task, int32_t delay_ms)
: task_(std::move(task)), delay_ms_(delay_ms) {}
- void Run(double deadline_in_seconds) final {
+
+ void Run(double deadline_in_seconds) override {
base::OS::Sleep(base::TimeDelta::FromMicroseconds(delay_ms_));
task_->Run(deadline_in_seconds);
}
@@ -250,6 +262,29 @@ class DelayedTasksPlatform : public Platform {
int32_t delay_ms_;
};
+ class DelayedJob final : public JobTask {
+ public:
+ DelayedJob(std::unique_ptr<JobTask> job_task, int32_t delay_ms)
+ : job_task_(std::move(job_task)), delay_ms_(delay_ms) {}
+
+ void Run(JobDelegate* delegate) override {
+ // If this job is being executed via worker tasks (as e.g. the
+ // {DefaultJobHandle} implementation does it), the worker task would
+ // already include a delay. In order to not depend on that, we add our own
+ // delay here anyway.
+ base::OS::Sleep(base::TimeDelta::FromMicroseconds(delay_ms_));
+ job_task_->Run(delegate);
+ }
+
+ size_t GetMaxConcurrency() const override {
+ return job_task_->GetMaxConcurrency();
+ }
+
+ private:
+ std::unique_ptr<JobTask> job_task_;
+ int32_t delay_ms_;
+ };
+
std::unique_ptr<Platform> platform_;
// The Mutex protects the RNG, which is used by foreground and background
@@ -279,6 +314,11 @@ class DelayedTasksPlatform : public Platform {
GetRandomDelayInMilliseconds());
}
+ std::unique_ptr<JobTask> MakeDelayedJob(std::unique_ptr<JobTask> task) {
+ return std::make_unique<DelayedJob>(std::move(task),
+ GetRandomDelayInMilliseconds());
+ }
+
DISALLOW_COPY_AND_ASSIGN(DelayedTasksPlatform);
};
diff --git a/chromium/v8/src/d8/d8.cc b/chromium/v8/src/d8/d8.cc
index 117df1cc526..26ccb62c681 100644
--- a/chromium/v8/src/d8/d8.cc
+++ b/chromium/v8/src/d8/d8.cc
@@ -36,7 +36,9 @@
#include "src/d8/d8.h"
#include "src/debug/debug-interface.h"
#include "src/deoptimizer/deoptimizer.h"
+#include "src/diagnostics/basic-block-profiler.h"
#include "src/execution/vm-state-inl.h"
+#include "src/flags/flags.h"
#include "src/handles/maybe-handles.h"
#include "src/init/v8.h"
#include "src/interpreter/interpreter.h"
@@ -50,6 +52,7 @@
#include "src/profiler/profile-generator.h"
#include "src/sanitizer/msan.h"
#include "src/snapshot/snapshot.h"
+#include "src/tasks/cancelable-task.h"
#include "src/trap-handler/trap-handler.h"
#include "src/utils/ostreams.h"
#include "src/utils/utils.h"
@@ -336,10 +339,9 @@ static MaybeLocal<Value> TryGetValue(v8::Isolate* isolate,
Local<Context> context,
Local<v8::Object> object,
const char* property) {
- Local<String> v8_str =
- String::NewFromUtf8(isolate, property).FromMaybe(Local<String>());
- if (v8_str.IsEmpty()) return Local<Value>();
- return object->Get(context, v8_str);
+ MaybeLocal<String> v8_str = String::NewFromUtf8(isolate, property);
+ if (v8_str.IsEmpty()) return {};
+ return object->Get(context, v8_str.ToLocalChecked());
}
static Local<Value> GetValue(v8::Isolate* isolate, Local<Context> context,
@@ -347,7 +349,8 @@ static Local<Value> GetValue(v8::Isolate* isolate, Local<Context> context,
return TryGetValue(isolate, context, object, property).ToLocalChecked();
}
-Worker* GetWorkerFromInternalField(Isolate* isolate, Local<Object> object) {
+std::shared_ptr<Worker> GetWorkerFromInternalField(Isolate* isolate,
+ Local<Object> object) {
if (object->InternalFieldCount() != 1) {
Throw(isolate, "this is not a Worker");
return nullptr;
@@ -359,7 +362,7 @@ Worker* GetWorkerFromInternalField(Isolate* isolate, Local<Object> object) {
return nullptr;
}
auto managed = i::Handle<i::Managed<Worker>>::cast(handle);
- return managed->raw();
+ return managed->get();
}
base::Thread::Options GetThreadOptions(const char* name) {
@@ -1182,10 +1185,9 @@ void PerIsolateData::AddUnhandledPromise(Local<Promise> promise,
Local<Message> message,
Local<Value> exception) {
DCHECK_EQ(promise->GetIsolate(), isolate_);
- unhandled_promises_.push_back(
- std::make_tuple(v8::Global<v8::Promise>(isolate_, promise),
- v8::Global<v8::Message>(isolate_, message),
- v8::Global<v8::Value>(isolate_, exception)));
+ unhandled_promises_.emplace_back(v8::Global<v8::Promise>(isolate_, promise),
+ v8::Global<v8::Message>(isolate_, message),
+ v8::Global<v8::Value>(isolate_, exception));
}
size_t PerIsolateData::GetUnhandledPromiseCount() {
@@ -1193,16 +1195,17 @@ size_t PerIsolateData::GetUnhandledPromiseCount() {
}
int PerIsolateData::HandleUnhandledPromiseRejections() {
- int unhandled_promises_count = 0;
v8::HandleScope scope(isolate_);
- for (auto& tuple : unhandled_promises_) {
+ // Ignore promises that get added during error reporting.
+ size_t unhandled_promises_count = unhandled_promises_.size();
+ for (size_t i = 0; i < unhandled_promises_count; i++) {
+ const auto& tuple = unhandled_promises_[i];
Local<v8::Message> message = std::get<1>(tuple).Get(isolate_);
Local<v8::Value> value = std::get<2>(tuple).Get(isolate_);
Shell::ReportException(isolate_, message, value);
- unhandled_promises_count++;
}
unhandled_promises_.clear();
- return unhandled_promises_count;
+ return static_cast<int>(unhandled_promises_count);
}
PerIsolateData::RealmScope::RealmScope(PerIsolateData* data) : data_(data) {
@@ -1684,8 +1687,10 @@ void Shell::WorkerNew(const v8::FunctionCallbackInfo<v8::Value>& args) {
if (args.Length() > 1 && args[1]->IsObject()) {
Local<Object> object = args[1].As<Object>();
Local<Context> context = isolate->GetCurrentContext();
- Local<Value> value = GetValue(args.GetIsolate(), context, object, "type");
- if (value->IsString()) {
+ Local<Value> value;
+ if (TryGetValue(args.GetIsolate(), context, object, "type")
+ .ToLocal(&value) &&
+ value->IsString()) {
Local<String> worker_type = value->ToString(context).ToLocalChecked();
String::Utf8Value str(isolate, worker_type);
if (strcmp("string", *str) == 0) {
@@ -1758,8 +1763,9 @@ void Shell::WorkerPostMessage(const v8::FunctionCallbackInfo<v8::Value>& args) {
return;
}
- Worker* worker = GetWorkerFromInternalField(isolate, args.Holder());
- if (!worker) {
+ std::shared_ptr<Worker> worker =
+ GetWorkerFromInternalField(isolate, args.Holder());
+ if (!worker.get()) {
return;
}
@@ -1776,8 +1782,9 @@ void Shell::WorkerPostMessage(const v8::FunctionCallbackInfo<v8::Value>& args) {
void Shell::WorkerGetMessage(const v8::FunctionCallbackInfo<v8::Value>& args) {
Isolate* isolate = args.GetIsolate();
HandleScope handle_scope(isolate);
- Worker* worker = GetWorkerFromInternalField(isolate, args.Holder());
- if (!worker) {
+ std::shared_ptr<Worker> worker =
+ GetWorkerFromInternalField(isolate, args.Holder());
+ if (!worker.get()) {
return;
}
@@ -1793,14 +1800,28 @@ void Shell::WorkerGetMessage(const v8::FunctionCallbackInfo<v8::Value>& args) {
void Shell::WorkerTerminate(const v8::FunctionCallbackInfo<v8::Value>& args) {
Isolate* isolate = args.GetIsolate();
HandleScope handle_scope(isolate);
- Worker* worker = GetWorkerFromInternalField(isolate, args.Holder());
- if (!worker) {
+ std::shared_ptr<Worker> worker =
+ GetWorkerFromInternalField(isolate, args.Holder());
+ if (!worker.get()) {
return;
}
worker->Terminate();
}
+void Shell::WorkerTerminateAndWait(
+ const v8::FunctionCallbackInfo<v8::Value>& args) {
+ Isolate* isolate = args.GetIsolate();
+ HandleScope handle_scope(isolate);
+ std::shared_ptr<Worker> worker =
+ GetWorkerFromInternalField(isolate, args.Holder());
+ if (!worker.get()) {
+ return;
+ }
+
+ worker->TerminateAndWaitForThread();
+}
+
void Shell::QuitOnce(v8::FunctionCallbackInfo<v8::Value>* args) {
int exit_code = (*args)[0]
->Int32Value(args->GetIsolate()->GetCurrentContext())
@@ -2131,6 +2152,10 @@ Local<ObjectTemplate> Shell::CreateGlobalTemplate(Isolate* isolate) {
FunctionTemplate::New(isolate, WorkerTerminate, Local<Value>(),
worker_signature));
worker_fun_template->PrototypeTemplate()->Set(
+ isolate, "terminateAndWait",
+ FunctionTemplate::New(isolate, WorkerTerminateAndWait, Local<Value>(),
+ worker_signature));
+ worker_fun_template->PrototypeTemplate()->Set(
isolate, "postMessage",
FunctionTemplate::New(isolate, WorkerPostMessage, Local<Value>(),
worker_signature));
@@ -2267,6 +2292,12 @@ void Shell::Initialize(Isolate* isolate, D8Console* console,
#ifdef V8_FUZZILLI
// Let the parent process (Fuzzilli) know we are ready.
+ if (options.fuzzilli_enable_builtins_coverage) {
+ cov_init_builtins_edges(static_cast<uint32_t>(
+ i::BasicBlockProfiler::Get()
+ ->GetCoverageBitmap(reinterpret_cast<i::Isolate*>(isolate))
+ .size()));
+ }
char helo[] = "HELO";
if (write(REPRL_CWFD, helo, 4) != 4 || read(REPRL_CRFD, helo, 4) != 4) {
fuzzilli_reprl = false;
@@ -2934,14 +2965,13 @@ void SerializationDataQueue::Clear() {
data_.clear();
}
-Worker::Worker(const char* script)
- : in_semaphore_(0),
- out_semaphore_(0),
- thread_(nullptr),
- script_(i::StrDup(script)),
- running_(false) {}
+Worker::Worker(const char* script) : script_(i::StrDup(script)) {
+ running_.store(false);
+}
Worker::~Worker() {
+ DCHECK_NULL(isolate_);
+
delete thread_;
thread_ = nullptr;
delete[] script_;
@@ -2949,10 +2979,12 @@ Worker::~Worker() {
}
bool Worker::StartWorkerThread(std::shared_ptr<Worker> worker) {
- worker->running_ = true;
+ worker->running_.store(true);
auto thread = new WorkerThread(worker);
worker->thread_ = thread;
if (thread->Start()) {
+ // Wait until the worker is ready to receive messages.
+ worker->started_semaphore_.Wait();
Shell::AddRunningWorker(std::move(worker));
return true;
}
@@ -2971,54 +3003,156 @@ void Worker::WorkerThread::Run() {
Shell::RemoveRunningWorker(worker);
}
+class ProcessMessageTask : public i::CancelableTask {
+ public:
+ ProcessMessageTask(i::CancelableTaskManager* task_manager,
+ std::shared_ptr<Worker> worker,
+ std::unique_ptr<SerializationData> data)
+ : i::CancelableTask(task_manager),
+ worker_(worker),
+ data_(std::move(data)) {}
+
+ void RunInternal() override { worker_->ProcessMessage(std::move(data_)); }
+
+ private:
+ std::shared_ptr<Worker> worker_;
+ std::unique_ptr<SerializationData> data_;
+};
+
void Worker::PostMessage(std::unique_ptr<SerializationData> data) {
- in_queue_.Enqueue(std::move(data));
- in_semaphore_.Signal();
+ // Hold the worker_mutex_ so that the worker thread can't delete task_runner_
+ // after we've checked running_.
+ base::MutexGuard lock_guard(&worker_mutex_);
+ if (!running_.load()) {
+ return;
+ }
+ std::unique_ptr<v8::Task> task(new ProcessMessageTask(
+ task_manager_, shared_from_this(), std::move(data)));
+ task_runner_->PostNonNestableTask(std::move(task));
}
+class TerminateTask : public i::CancelableTask {
+ public:
+ TerminateTask(i::CancelableTaskManager* task_manager,
+ std::shared_ptr<Worker> worker)
+ : i::CancelableTask(task_manager), worker_(worker) {}
+
+ void RunInternal() override {
+ // Make sure the worker doesn't enter the task loop after processing this
+ // task.
+ worker_->running_.store(false);
+ }
+
+ private:
+ std::shared_ptr<Worker> worker_;
+};
+
std::unique_ptr<SerializationData> Worker::GetMessage() {
std::unique_ptr<SerializationData> result;
while (!out_queue_.Dequeue(&result)) {
// If the worker is no longer running, and there are no messages in the
// queue, don't expect any more messages from it.
- if (!base::Relaxed_Load(&running_)) break;
+ if (!running_.load()) {
+ break;
+ }
out_semaphore_.Wait();
}
return result;
}
void Worker::Terminate() {
- base::Relaxed_Store(&running_, false);
- // Post nullptr to wake the Worker thread message loop, and tell it to stop
- // running.
- PostMessage(nullptr);
+ // Hold the worker_mutex_ so that the worker thread can't delete task_runner_
+ // after we've checked running_.
+ base::MutexGuard lock_guard(&worker_mutex_);
+ if (!running_.load()) {
+ return;
+ }
+ // Post a task to wake up the worker thread.
+ std::unique_ptr<v8::Task> task(
+ new TerminateTask(task_manager_, shared_from_this()));
+ task_runner_->PostTask(std::move(task));
}
-void Worker::WaitForThread() {
+void Worker::TerminateAndWaitForThread() {
Terminate();
thread_->Join();
}
+void Worker::ProcessMessage(std::unique_ptr<SerializationData> data) {
+ if (!running_.load()) {
+ return;
+ }
+
+ DCHECK_NOT_NULL(isolate_);
+ HandleScope scope(isolate_);
+ Local<Context> context = context_.Get(isolate_);
+ Context::Scope cscope(context);
+ Local<Object> global = context->Global();
+
+ // Get the message handler.
+ Local<Value> onmessage = global
+ ->Get(context, String::NewFromUtf8Literal(
+ isolate_, "onmessage",
+ NewStringType::kInternalized))
+ .ToLocalChecked();
+ if (!onmessage->IsFunction()) {
+ return;
+ }
+ Local<Function> onmessage_fun = Local<Function>::Cast(onmessage);
+
+ v8::TryCatch try_catch(isolate_);
+ try_catch.SetVerbose(true);
+ Local<Value> value;
+ if (Shell::DeserializeValue(isolate_, std::move(data)).ToLocal(&value)) {
+ Local<Value> argv[] = {value};
+ MaybeLocal<Value> result = onmessage_fun->Call(context, global, 1, argv);
+ USE(result);
+ }
+}
+
+void Worker::ProcessMessages() {
+ i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate_);
+ i::SaveAndSwitchContext saved_context(i_isolate, i::Context());
+ SealHandleScope shs(isolate_);
+ while (running_.load() && v8::platform::PumpMessageLoop(
+ g_default_platform, isolate_,
+ platform::MessageLoopBehavior::kWaitForWork)) {
+ if (running_.load()) {
+ MicrotasksScope::PerformCheckpoint(isolate_);
+ }
+ }
+}
+
void Worker::ExecuteInThread() {
Isolate::CreateParams create_params;
create_params.array_buffer_allocator = Shell::array_buffer_allocator;
- Isolate* isolate = Isolate::New(create_params);
- D8Console console(isolate);
- Shell::Initialize(isolate, &console, false);
+ isolate_ = Isolate::New(create_params);
{
- Isolate::Scope iscope(isolate);
+ base::MutexGuard lock_guard(&worker_mutex_);
+ task_runner_ = g_default_platform->GetForegroundTaskRunner(isolate_);
+ task_manager_ =
+ reinterpret_cast<i::Isolate*>(isolate_)->cancelable_task_manager();
+ }
+ // The Worker is now ready to receive messages.
+ started_semaphore_.Signal();
+
+ D8Console console(isolate_);
+ Shell::Initialize(isolate_, &console, false);
+ {
+ Isolate::Scope iscope(isolate_);
{
- HandleScope scope(isolate);
- PerIsolateData data(isolate);
- Local<Context> context = Shell::CreateEvaluationContext(isolate);
+ HandleScope scope(isolate_);
+ PerIsolateData data(isolate_);
+ Local<Context> context = Shell::CreateEvaluationContext(isolate_);
+ context_.Reset(isolate_, context);
{
Context::Scope cscope(context);
- PerIsolateData::RealmScope realm_scope(PerIsolateData::Get(isolate));
+ PerIsolateData::RealmScope realm_scope(PerIsolateData::Get(isolate_));
Local<Object> global = context->Global();
- Local<Value> this_value = External::New(isolate, this);
+ Local<Value> this_value = External::New(isolate_, this);
Local<FunctionTemplate> postmessage_fun_template =
- FunctionTemplate::New(isolate, PostMessageOut, this_value);
+ FunctionTemplate::New(isolate_, PostMessageOut, this_value);
Local<Function> postmessage_fun;
if (postmessage_fun_template->GetFunction(context).ToLocal(
@@ -3026,56 +3160,49 @@ void Worker::ExecuteInThread() {
global
->Set(context,
v8::String::NewFromUtf8Literal(
- isolate, "postMessage", NewStringType::kInternalized),
+ isolate_, "postMessage", NewStringType::kInternalized),
postmessage_fun)
.FromJust();
}
// First run the script
Local<String> file_name =
- String::NewFromUtf8Literal(isolate, "unnamed");
+ String::NewFromUtf8Literal(isolate_, "unnamed");
Local<String> source =
- String::NewFromUtf8(isolate, script_).ToLocalChecked();
+ String::NewFromUtf8(isolate_, script_).ToLocalChecked();
if (Shell::ExecuteString(
- isolate, source, file_name, Shell::kNoPrintResult,
+ isolate_, source, file_name, Shell::kNoPrintResult,
Shell::kReportExceptions, Shell::kProcessMessageQueue)) {
- // Get the message handler
+ // Check that there's a message handler
Local<Value> onmessage =
global
- ->Get(context,
- String::NewFromUtf8Literal(
- isolate, "onmessage", NewStringType::kInternalized))
+ ->Get(context, String::NewFromUtf8Literal(
+ isolate_, "onmessage",
+ NewStringType::kInternalized))
.ToLocalChecked();
if (onmessage->IsFunction()) {
- Local<Function> onmessage_fun = Local<Function>::Cast(onmessage);
- SealHandleScope shs(isolate);
// Now wait for messages
- while (true) {
- in_semaphore_.Wait();
- std::unique_ptr<SerializationData> data;
- if (!in_queue_.Dequeue(&data)) continue;
- if (!data) break;
- v8::TryCatch try_catch(isolate);
- try_catch.SetVerbose(true);
- HandleScope scope(isolate);
- Local<Value> value;
- if (Shell::DeserializeValue(isolate, std::move(data))
- .ToLocal(&value)) {
- Local<Value> argv[] = {value};
- MaybeLocal<Value> result =
- onmessage_fun->Call(context, global, 1, argv);
- USE(result);
- }
- }
- // TODO(cbruni): Check for unhandled promises here.
+ ProcessMessages();
}
}
}
DisposeModuleEmbedderData(context);
}
- Shell::CollectGarbage(isolate);
+ Shell::CollectGarbage(isolate_);
}
- isolate->Dispose();
+ // TODO(cbruni): Check for unhandled promises here.
+ {
+ // Hold the mutex to ensure running_ and task_runner_ change state
+ // atomically (see Worker::PostMessage which reads them).
+ base::MutexGuard lock_guard(&worker_mutex_);
+ running_.store(false);
+ task_runner_.reset();
+ task_manager_ = nullptr;
+ }
+ context_.Reset();
+ platform::NotifyIsolateShutdown(g_default_platform, isolate_);
+ isolate_->Dispose();
+ isolate_ = nullptr;
// Post nullptr to wake the thread waiting on GetMessage() if there is one.
out_queue_.Enqueue(nullptr);
@@ -3159,10 +3286,10 @@ bool Shell::SetOptions(int argc, char* argv[]) {
} else if (strcmp(argv[i], "--omit-quit") == 0) {
options.omit_quit = true;
argv[i] = nullptr;
- } else if (strcmp(argv[i], "--no-wait-for-wasm") == 0) {
+ } else if (strcmp(argv[i], "--no-wait-for-background-tasks") == 0) {
// TODO(herhut) Remove this flag once wasm compilation is fully
// isolate-independent.
- options.wait_for_wasm = false;
+ options.wait_for_background_tasks = false;
argv[i] = nullptr;
} else if (strcmp(argv[i], "-f") == 0) {
// Ignore any -f flags for compatibility with other stand-alone
@@ -3261,13 +3388,30 @@ bool Shell::SetOptions(int argc, char* argv[]) {
options.cpu_profiler = true;
options.cpu_profiler_print = true;
argv[i] = nullptr;
+#ifdef V8_FUZZILLI
+ } else if (strcmp(argv[i], "--no-fuzzilli-enable-builtins-coverage") == 0) {
+ options.fuzzilli_enable_builtins_coverage = false;
+ argv[i] = nullptr;
+ } else if (strcmp(argv[i], "--fuzzilli-coverage-statistics") == 0) {
+ options.fuzzilli_coverage_statistics = true;
+ argv[i] = nullptr;
+#endif
} else if (strcmp(argv[i], "--fuzzy-module-file-extensions") == 0) {
options.fuzzy_module_file_extensions = true;
argv[i] = nullptr;
}
}
- v8::V8::SetFlagsFromCommandLine(&argc, argv, true);
+ const char* usage =
+ "Synopsis:\n"
+ " shell [options] [--shell] [<file>...]\n"
+ " d8 [options] [-e <string>] [--shell] [[--module] <file>...]\n\n"
+ " -e execute a string in V8\n"
+ " --shell run an interactive JavaScript shell\n"
+ " --module execute a file as a JavaScript module\n\n";
+ using HelpOptions = i::FlagList::HelpOptions;
+ i::FlagList::SetFlagsFromCommandLine(&argc, argv, true,
+ HelpOptions(HelpOptions::kExit, usage));
options.mock_arraybuffer_allocator = i::FLAG_mock_arraybuffer_allocator;
options.mock_arraybuffer_allocator_limit =
i::FLAG_mock_arraybuffer_allocator_limit;
@@ -3457,10 +3601,8 @@ bool Shell::CompleteMessageLoop(Isolate* isolate) {
auto get_waiting_behaviour = [isolate]() {
base::MutexGuard guard(isolate_status_lock_.Pointer());
DCHECK_GT(isolate_status_.count(isolate), 0);
- i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
- i::wasm::WasmEngine* wasm_engine = i_isolate->wasm_engine();
- bool should_wait = (options.wait_for_wasm &&
- wasm_engine->HasRunningCompileJob(i_isolate)) ||
+ bool should_wait = (options.wait_for_background_tasks &&
+ isolate->HasPendingBackgroundTasks()) ||
isolate_status_[isolate] ||
isolate_running_streaming_tasks_[isolate] > 0;
return should_wait ? platform::MessageLoopBehavior::kWaitForWork
@@ -3790,7 +3932,7 @@ void Shell::WaitForRunningWorkers() {
}
for (auto& worker : workers_copy) {
- worker->WaitForThread();
+ worker->TerminateAndWaitForThread();
}
// Now that all workers are terminated, we can re-enable Worker creation.
@@ -4055,13 +4197,34 @@ int Shell::Main(int argc, char* argv[]) {
evaluation_context_.Reset();
stringify_function_.Reset();
CollectGarbage(isolate);
-
#ifdef V8_FUZZILLI
// Send result to parent (fuzzilli) and reset edge guards.
if (fuzzilli_reprl) {
int status = result << 8;
+ std::vector<bool> bitmap;
+ if (options.fuzzilli_enable_builtins_coverage) {
+ bitmap = i::BasicBlockProfiler::Get()->GetCoverageBitmap(
+ reinterpret_cast<i::Isolate*>(isolate));
+ cov_update_builtins_basic_block_coverage(bitmap);
+ }
+ if (options.fuzzilli_coverage_statistics) {
+ int tot = 0;
+ for (bool b : bitmap) {
+ if (b) tot++;
+ }
+ static int iteration_counter = 0;
+ std::ofstream covlog("covlog.txt", std::ios::app);
+ covlog << iteration_counter << "\t" << tot << "\t"
+ << sanitizer_cov_count_discovered_edges() << "\t"
+ << bitmap.size() << std::endl;
+ iteration_counter++;
+ }
CHECK_EQ(write(REPRL_CWFD, &status, 4), 4);
- __sanitizer_cov_reset_edgeguards();
+ sanitizer_cov_reset_edgeguards();
+ if (options.fuzzilli_enable_builtins_coverage) {
+ i::BasicBlockProfiler::Get()->ResetCounts(
+ reinterpret_cast<i::Isolate*>(isolate));
+ }
}
#endif // V8_FUZZILLI
} while (fuzzilli_reprl);
diff --git a/chromium/v8/src/d8/d8.h b/chromium/v8/src/d8/d8.h
index 203e9edb0cb..6b2c08fd6ea 100644
--- a/chromium/v8/src/d8/d8.h
+++ b/chromium/v8/src/d8/d8.h
@@ -25,6 +25,10 @@ namespace v8 {
class D8Console;
+namespace internal {
+class CancelableTaskManager;
+} // namespace internal
+
// A single counter in a counter collection.
class Counter {
public:
@@ -158,14 +162,14 @@ class SerializationDataQueue {
std::vector<std::unique_ptr<SerializationData>> data_;
};
-class Worker {
+class Worker : public std::enable_shared_from_this<Worker> {
public:
explicit Worker(const char* script);
~Worker();
- // Post a message to the worker's incoming message queue. The worker will
- // take ownership of the SerializationData.
- // This function should only be called by the thread that created the Worker.
+ // Post a message to the worker. The worker will take ownership of the
+ // SerializationData. This function should only be called by the thread that
+ // created the Worker.
void PostMessage(std::unique_ptr<SerializationData> data);
// Synchronously retrieve messages from the worker's outgoing message queue.
// If there is no message in the queue, block until a message is available.
@@ -179,12 +183,18 @@ class Worker {
void Terminate();
// Terminate and join the thread.
// This function can be called by any thread.
- void WaitForThread();
+ void TerminateAndWaitForThread();
// Start running the given worker in another thread.
static bool StartWorkerThread(std::shared_ptr<Worker> worker);
private:
+ friend class ProcessMessageTask;
+ friend class TerminateTask;
+
+ void ProcessMessage(std::unique_ptr<SerializationData> data);
+ void ProcessMessages();
+
class WorkerThread : public base::Thread {
public:
explicit WorkerThread(std::shared_ptr<Worker> worker)
@@ -200,13 +210,25 @@ class Worker {
void ExecuteInThread();
static void PostMessageOut(const v8::FunctionCallbackInfo<v8::Value>& args);
- base::Semaphore in_semaphore_;
- base::Semaphore out_semaphore_;
- SerializationDataQueue in_queue_;
+ base::Semaphore out_semaphore_{0};
SerializationDataQueue out_queue_;
- base::Thread* thread_;
+ base::Thread* thread_ = nullptr;
char* script_;
- base::Atomic32 running_;
+ std::atomic<bool> running_;
+ // For signalling that the worker has started.
+ base::Semaphore started_semaphore_{0};
+
+ // For posting tasks to the worker
+ std::shared_ptr<TaskRunner> task_runner_;
+ i::CancelableTaskManager* task_manager_;
+
+ // Protects reading / writing task_runner_. (The TaskRunner itself doesn't
+ // need locking, but accessing the Worker's data member does.)
+ base::Mutex worker_mutex_;
+
+ // Only accessed by the worker thread.
+ Isolate* isolate_ = nullptr;
+ v8::Persistent<v8::Context> context_;
};
class PerIsolateData {
@@ -270,10 +292,12 @@ class ShellOptions {
~ShellOptions() { delete[] isolate_sources; }
+ bool fuzzilli_coverage_statistics = false;
+ bool fuzzilli_enable_builtins_coverage = true;
bool send_idle_notification = false;
bool invoke_weak_callbacks = false;
bool omit_quit = false;
- bool wait_for_wasm = true;
+ bool wait_for_background_tasks = true;
bool stress_opt = false;
int stress_runs = 1;
bool stress_snapshot = false;
@@ -405,6 +429,8 @@ class Shell : public i::AllStatic {
const v8::FunctionCallbackInfo<v8::Value>& args);
static void WorkerGetMessage(const v8::FunctionCallbackInfo<v8::Value>& args);
static void WorkerTerminate(const v8::FunctionCallbackInfo<v8::Value>& args);
+ static void WorkerTerminateAndWait(
+ const v8::FunctionCallbackInfo<v8::Value>& args);
// The OS object on the global object contains methods for performing
// operating system calls:
//