diff options
author | Myles Borins <mylesborins@google.com> | 2019-09-24 11:56:38 -0400 |
---|---|---|
committer | Myles Borins <myles.borins@gmail.com> | 2019-10-07 03:19:23 -0400 |
commit | f7f6c928c1c9c136b7926f892b8a2fda11d8b4b2 (patch) | |
tree | f5edbccb3ffda2573d70a6e291e7157f290e0ae0 /deps/v8/src/d8 | |
parent | ffd22e81983056d09c064c59343a0e488236272d (diff) | |
download | android-node-v8-f7f6c928c1c9c136b7926f892b8a2fda11d8b4b2.tar.gz android-node-v8-f7f6c928c1c9c136b7926f892b8a2fda11d8b4b2.tar.bz2 android-node-v8-f7f6c928c1c9c136b7926f892b8a2fda11d8b4b2.zip |
deps: update V8 to 7.8.279.9
PR-URL: https://github.com/nodejs/node/pull/29694
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Gus Caplan <me@gus.host>
Reviewed-By: Jiawen Geng <technicalcute@gmail.com>
Reviewed-By: Michaël Zasso <targos@protonmail.com>
Reviewed-By: Tobias Nießen <tniessen@tnie.de>
Reviewed-By: Ujjwal Sharma <usharma1998@gmail.com>
Diffstat (limited to 'deps/v8/src/d8')
-rw-r--r-- | deps/v8/src/d8/d8.cc | 203 | ||||
-rw-r--r-- | deps/v8/src/d8/d8.h | 29 |
2 files changed, 168 insertions, 64 deletions
diff --git a/deps/v8/src/d8/d8.cc b/deps/v8/src/d8/d8.cc index 6656ab608d..13a35b0cd3 100644 --- a/deps/v8/src/d8/d8.cc +++ b/deps/v8/src/d8/d8.cc @@ -36,6 +36,7 @@ #include "src/init/v8.h" #include "src/interpreter/interpreter.h" #include "src/logging/counters.h" +#include "src/objects/managed.h" #include "src/objects/objects-inl.h" #include "src/objects/objects.h" #include "src/parsing/parse-info.h" @@ -76,7 +77,6 @@ namespace { const int kMB = 1024 * 1024; -const int kMaxWorkers = 100; const int kMaxSerializerMemoryUsage = 1 * kMB; // Arbitrary maximum for testing. @@ -227,14 +227,13 @@ Worker* GetWorkerFromInternalField(Isolate* isolate, Local<Object> object) { return nullptr; } - Worker* worker = - static_cast<Worker*>(object->GetAlignedPointerFromInternalField(0)); - if (worker == nullptr) { + i::Handle<i::Object> handle = Utils::OpenHandle(*object->GetInternalField(0)); + if (handle->IsSmi()) { Throw(isolate, "Worker is defunct because main thread is terminating"); return nullptr; } - - return worker; + auto managed = i::Handle<i::Managed<Worker>>::cast(handle); + return managed->raw(); } base::Thread::Options GetThreadOptions(const char* name) { @@ -333,7 +332,7 @@ const base::TimeTicks Shell::kInitialTicks = Global<Function> Shell::stringify_function_; base::LazyMutex Shell::workers_mutex_; bool Shell::allow_new_workers_ = true; -std::vector<Worker*> Shell::workers_; +std::unordered_set<std::shared_ptr<Worker>> Shell::running_workers_; std::vector<ExternalizedContents> Shell::externalized_contents_; std::atomic<bool> Shell::script_executed_{false}; base::LazyMutex Shell::isolate_status_lock_; @@ -485,7 +484,7 @@ bool Shell::ExecuteString(Isolate* isolate, Local<String> source, } else if (options.stress_background_compile) { // Start a background thread compiling the script. BackgroundCompileThread background_compile_thread(isolate, source); - background_compile_thread.Start(); + CHECK(background_compile_thread.Start()); // In parallel, compile on the main thread to flush out any data races. { @@ -762,6 +761,16 @@ MaybeLocal<Promise> Shell::HostImportModuleDynamically( return MaybeLocal<Promise>(); } +void Shell::HostCleanupFinalizationGroup(Local<Context> context, + Local<FinalizationGroup> fg) { + Isolate* isolate = context->GetIsolate(); + PerIsolateData::Get(isolate)->HostCleanupFinalizationGroup(fg); +} + +void PerIsolateData::HostCleanupFinalizationGroup(Local<FinalizationGroup> fg) { + cleanup_finalization_groups_.emplace(isolate_, fg); +} + void Shell::HostInitializeImportMetaObject(Local<Context> context, Local<Module> module, Local<Object> meta) { @@ -908,6 +917,15 @@ MaybeLocal<Context> PerIsolateData::GetTimeoutContext() { return result; } +MaybeLocal<FinalizationGroup> PerIsolateData::GetCleanupFinalizationGroup() { + if (cleanup_finalization_groups_.empty()) + return MaybeLocal<FinalizationGroup>(); + Local<FinalizationGroup> result = + cleanup_finalization_groups_.front().Get(isolate_); + cleanup_finalization_groups_.pop(); + return result; +} + PerIsolateData::RealmScope::RealmScope(PerIsolateData* data) : data_(data) { data_->realm_count_ = 1; data_->realm_current_ = 0; @@ -1392,30 +1410,36 @@ void Shell::WorkerNew(const v8::FunctionCallbackInfo<v8::Value>& args) { return; } + // Initialize the embedder field to 0; if we return early without + // creating a new Worker (because the main thread is terminating) we can + // early-out from the instance calls. + args.Holder()->SetInternalField(0, v8::Integer::New(isolate, 0)); + { + // Don't allow workers to create more workers if the main thread + // is waiting for existing running workers to terminate. base::MutexGuard lock_guard(workers_mutex_.Pointer()); - if (workers_.size() >= kMaxWorkers) { - Throw(args.GetIsolate(), "Too many workers, I won't let you create more"); - return; - } - - // Initialize the embedder field to nullptr; if we return early without - // creating a new Worker (because the main thread is terminating) we can - // early-out from the instance calls. - args.Holder()->SetAlignedPointerInInternalField(0, nullptr); - if (!allow_new_workers_) return; - Worker* worker = new Worker; - args.Holder()->SetAlignedPointerInInternalField(0, worker); - workers_.push_back(worker); - String::Utf8Value script(args.GetIsolate(), source); if (!*script) { Throw(args.GetIsolate(), "Can't get worker script"); return; } - worker->StartExecuteInThread(*script); + + // The C++ worker object's lifetime is shared between the Managed<Worker> + // object on the heap, which the JavaScript object points to, and an + // internal std::shared_ptr in the worker thread itself. + auto worker = std::make_shared<Worker>(*script); + i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate); + const size_t kWorkerSizeEstimate = 4 * 1024 * 1024; // stack + heap. + i::Handle<i::Object> managed = i::Managed<Worker>::FromSharedPtr( + i_isolate, kWorkerSizeEstimate, worker); + args.Holder()->SetInternalField(0, Utils::ToLocal(managed)); + if (!Worker::StartWorkerThread(std::move(worker))) { + Throw(args.GetIsolate(), "Can't start thread"); + return; + } } } @@ -1475,7 +1499,7 @@ void Shell::QuitOnce(v8::FunctionCallbackInfo<v8::Value>* args) { int exit_code = (*args)[0] ->Int32Value(args->GetIsolate()->GetCurrentContext()) .FromMaybe(0); - CleanupWorkers(); + WaitForRunningWorkers(); args->GetIsolate()->Exit(); OnExit(args->GetIsolate()); base::OS::ExitProcess(exit_code); @@ -1920,6 +1944,9 @@ Local<Context> Shell::CreateEvaluationContext(Isolate* isolate) { EscapableHandleScope handle_scope(isolate); Local<Context> context = Context::New(isolate, nullptr, global_template); DCHECK(!context.IsEmpty()); + if (i::FLAG_perf_prof_annotate_wasm) { + isolate->SetWasmLoadSourceMapCallback(ReadFile); + } InitializeModuleEmbedderData(context); if (options.include_arguments) { Context::Scope scope(context); @@ -2468,6 +2495,8 @@ void SourceGroup::ExecuteInThread() { Isolate::CreateParams create_params; create_params.array_buffer_allocator = Shell::array_buffer_allocator; Isolate* isolate = Isolate::New(create_params); + isolate->SetHostCleanupFinalizationGroupCallback( + Shell::HostCleanupFinalizationGroup); isolate->SetHostImportModuleDynamicallyCallback( Shell::HostImportModuleDynamically); isolate->SetHostInitializeImportMetaObjectCallback( @@ -2504,7 +2533,7 @@ void SourceGroup::ExecuteInThread() { void SourceGroup::StartExecuteInThread() { if (thread_ == nullptr) { thread_ = new IsolateThread(this); - thread_->Start(); + CHECK(thread_->Start()); } next_semaphore_.Signal(); } @@ -2550,11 +2579,11 @@ void SerializationDataQueue::Clear() { data_.clear(); } -Worker::Worker() +Worker::Worker(const char* script) : in_semaphore_(0), out_semaphore_(0), thread_(nullptr), - script_(nullptr), + script_(i::StrDup(script)), running_(false) {} Worker::~Worker() { @@ -2562,15 +2591,29 @@ Worker::~Worker() { thread_ = nullptr; delete[] script_; script_ = nullptr; - in_queue_.Clear(); - out_queue_.Clear(); } -void Worker::StartExecuteInThread(const char* script) { - running_ = true; - script_ = i::StrDup(script); - thread_ = new WorkerThread(this); - thread_->Start(); +bool Worker::StartWorkerThread(std::shared_ptr<Worker> worker) { + worker->running_ = true; + auto thread = new WorkerThread(worker); + worker->thread_ = thread; + if (thread->Start()) { + Shell::AddRunningWorker(std::move(worker)); + return true; + } + return false; +} + +void Worker::WorkerThread::Run() { + // Prevent a lifetime cycle from Worker -> WorkerThread -> Worker. + // We must clear the worker_ field of the thread, but we keep the + // worker alive via a stack root until the thread finishes execution + // and removes itself from the running set. Thereafter the only + // remaining reference can be from a JavaScript object via a Managed. + auto worker = std::move(worker_); + worker_ = nullptr; + worker->ExecuteInThread(); + Shell::RemoveRunningWorker(worker); } void Worker::PostMessage(std::unique_ptr<SerializationData> data) { @@ -2605,6 +2648,8 @@ void Worker::ExecuteInThread() { Isolate::CreateParams create_params; create_params.array_buffer_allocator = Shell::array_buffer_allocator; Isolate* isolate = Isolate::New(create_params); + isolate->SetHostCleanupFinalizationGroupCallback( + Shell::HostCleanupFinalizationGroup); isolate->SetHostImportModuleDynamicallyCallback( Shell::HostImportModuleDynamically); isolate->SetHostInitializeImportMetaObjectCallback( @@ -2657,6 +2702,7 @@ void Worker::ExecuteInThread() { .ToLocalChecked(); if (onmessage->IsFunction()) { Local<Function> onmessage_fun = Local<Function>::Cast(onmessage); + SealHandleScope shs(isolate); // Now wait for messages while (true) { in_semaphore_.Wait(); @@ -2666,6 +2712,7 @@ void Worker::ExecuteInThread() { break; } v8::TryCatch try_catch(isolate); + HandleScope scope(isolate); Local<Value> value; if (Shell::DeserializeValue(isolate, std::move(data)) .ToLocal(&value)) { @@ -2936,7 +2983,7 @@ int Shell::RunMain(Isolate* isolate, int argc, char* argv[], bool last_run) { options.isolate_sources[i].WaitForThread(); } } - CleanupWorkers(); + WaitForRunningWorkers(); // In order to finish successfully, success must be != expected_to_throw. return success == Shell::options.expected_to_throw ? 1 : 0; } @@ -2966,6 +3013,40 @@ void Shell::SetWaitUntilDone(Isolate* isolate, bool value) { } namespace { +bool RunSetTimeoutCallback(Isolate* isolate, bool* did_run) { + PerIsolateData* data = PerIsolateData::Get(isolate); + HandleScope handle_scope(isolate); + Local<Function> callback; + if (!data->GetTimeoutCallback().ToLocal(&callback)) return true; + Local<Context> context; + if (!data->GetTimeoutContext().ToLocal(&context)) return true; + TryCatch try_catch(isolate); + try_catch.SetVerbose(true); + Context::Scope context_scope(context); + if (callback->Call(context, Undefined(isolate), 0, nullptr).IsEmpty()) { + Shell::ReportException(isolate, &try_catch); + return false; + } + *did_run = true; + return true; +} + +bool RunCleanupFinalizationGroupCallback(Isolate* isolate, bool* did_run) { + PerIsolateData* data = PerIsolateData::Get(isolate); + HandleScope handle_scope(isolate); + while (true) { + Local<FinalizationGroup> fg; + if (!data->GetCleanupFinalizationGroup().ToLocal(&fg)) return true; + *did_run = true; + TryCatch try_catch(isolate); + try_catch.SetVerbose(true); + if (FinalizationGroup::Cleanup(fg).IsNothing()) { + Shell::ReportException(isolate, &try_catch); + return false; + } + } +} + bool ProcessMessages( Isolate* isolate, const std::function<platform::MessageLoopBehavior()>& behavior) { @@ -2976,24 +3057,23 @@ bool ProcessMessages( while (v8::platform::PumpMessageLoop(g_default_platform, isolate, behavior())) { MicrotasksScope::PerformCheckpoint(isolate); + isolate->ClearKeptObjects(); } if (g_default_platform->IdleTasksEnabled(isolate)) { v8::platform::RunIdleTasks(g_default_platform, isolate, 50.0 / base::Time::kMillisecondsPerSecond); } - HandleScope handle_scope(isolate); - PerIsolateData* data = PerIsolateData::Get(isolate); - Local<Function> callback; - if (!data->GetTimeoutCallback().ToLocal(&callback)) break; - Local<Context> context; - if (!data->GetTimeoutContext().ToLocal(&context)) break; - TryCatch try_catch(isolate); - try_catch.SetVerbose(true); - Context::Scope context_scope(context); - if (callback->Call(context, Undefined(isolate), 0, nullptr).IsEmpty()) { - Shell::ReportException(isolate, &try_catch); + bool ran_finalization_callback = false; + if (!RunCleanupFinalizationGroupCallback(isolate, + &ran_finalization_callback)) { return false; } + bool ran_set_timeout = false; + if (!RunSetTimeoutCallback(isolate, &ran_set_timeout)) { + return false; + } + + if (!ran_set_timeout && !ran_finalization_callback) return true; } return true; } @@ -3267,24 +3347,35 @@ MaybeLocal<Value> Shell::DeserializeValue( return deserializer.ReadValue(context); } -void Shell::CleanupWorkers() { - // Make a copy of workers_, because we don't want to call Worker::Terminate - // while holding the workers_mutex_ lock. Otherwise, if a worker is about to - // create a new Worker, it would deadlock. - std::vector<Worker*> workers_copy; +void Shell::AddRunningWorker(std::shared_ptr<Worker> worker) { + workers_mutex_.Pointer()->AssertHeld(); // caller should hold the mutex. + running_workers_.insert(worker); +} + +void Shell::RemoveRunningWorker(const std::shared_ptr<Worker>& worker) { + base::MutexGuard lock_guard(workers_mutex_.Pointer()); + auto it = running_workers_.find(worker); + if (it != running_workers_.end()) running_workers_.erase(it); +} + +void Shell::WaitForRunningWorkers() { + // Make a copy of running_workers_, because we don't want to call + // Worker::Terminate while holding the workers_mutex_ lock. Otherwise, if a + // worker is about to create a new Worker, it would deadlock. + std::unordered_set<std::shared_ptr<Worker>> workers_copy; { base::MutexGuard lock_guard(workers_mutex_.Pointer()); allow_new_workers_ = false; - workers_copy.swap(workers_); + workers_copy.swap(running_workers_); } - for (Worker* worker : workers_copy) { + for (auto& worker : workers_copy) { worker->WaitForThread(); - delete worker; } // Now that all workers are terminated, we can re-enable Worker creation. base::MutexGuard lock_guard(workers_mutex_.Pointer()); + DCHECK(running_workers_.empty()); allow_new_workers_ = true; externalized_contents_.clear(); } @@ -3405,6 +3496,8 @@ int Shell::Main(int argc, char* argv[]) { } Isolate* isolate = Isolate::New(create_params); + isolate->SetHostCleanupFinalizationGroupCallback( + Shell::HostCleanupFinalizationGroup); isolate->SetHostImportModuleDynamicallyCallback( Shell::HostImportModuleDynamically); isolate->SetHostInitializeImportMetaObjectCallback( @@ -3462,6 +3555,8 @@ int Shell::Main(int argc, char* argv[]) { i::FLAG_hash_seed ^= 1337; // Use a different hash seed. Isolate* isolate2 = Isolate::New(create_params); i::FLAG_hash_seed ^= 1337; // Restore old hash seed. + isolate2->SetHostCleanupFinalizationGroupCallback( + Shell::HostCleanupFinalizationGroup); isolate2->SetHostImportModuleDynamicallyCallback( Shell::HostImportModuleDynamically); isolate2->SetHostInitializeImportMetaObjectCallback( diff --git a/deps/v8/src/d8/d8.h b/deps/v8/src/d8/d8.h index 1e0dd43c2d..04fc5f5d34 100644 --- a/deps/v8/src/d8/d8.h +++ b/deps/v8/src/d8/d8.h @@ -11,6 +11,7 @@ #include <queue> #include <string> #include <unordered_map> +#include <unordered_set> #include <vector> #include "src/base/once.h" @@ -207,12 +208,9 @@ class SerializationDataQueue { class Worker { public: - Worker(); + explicit Worker(const char* script); ~Worker(); - // Run the given script on this Worker. This function should only be called - // once, and should only be called by the thread that created the Worker. - void StartExecuteInThread(const char* script); // 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. @@ -231,17 +229,20 @@ class Worker { // This function can be called by any thread. void WaitForThread(); + // Start running the given worker in another thread. + static bool StartWorkerThread(std::shared_ptr<Worker> worker); + private: class WorkerThread : public base::Thread { public: - explicit WorkerThread(Worker* worker) + explicit WorkerThread(std::shared_ptr<Worker> worker) : base::Thread(base::Thread::Options("WorkerThread")), - worker_(worker) {} + worker_(std::move(worker)) {} - void Run() override { worker_->ExecuteInThread(); } + void Run() override; private: - Worker* worker_; + std::shared_ptr<Worker> worker_; }; void ExecuteInThread(); @@ -275,6 +276,8 @@ class PerIsolateData { PerIsolateData* data_; }; + inline void HostCleanupFinalizationGroup(Local<FinalizationGroup> fg); + inline MaybeLocal<FinalizationGroup> GetCleanupFinalizationGroup(); inline void SetTimeout(Local<Function> callback, Local<Context> context); inline MaybeLocal<Function> GetTimeoutCallback(); inline MaybeLocal<Context> GetTimeoutContext(); @@ -292,6 +295,7 @@ class PerIsolateData { Global<Value> realm_shared_; std::queue<Global<Function>> set_timeout_callbacks_; std::queue<Global<Context>> set_timeout_contexts_; + std::queue<Global<FinalizationGroup>> cleanup_finalization_groups_; AsyncHooks* async_hooks_wrapper_; int RealmIndexOrThrow(const v8::FunctionCallbackInfo<v8::Value>& args, @@ -378,7 +382,6 @@ class Shell : public i::AllStatic { Isolate* isolate, Local<Value> value, Local<Value> transfer); static MaybeLocal<Value> DeserializeValue( Isolate* isolate, std::unique_ptr<SerializationData> data); - static void CleanupWorkers(); static int* LookupCounter(const char* name); static void* CreateHistogram(const char* name, int min, int max, size_t buckets); @@ -465,6 +468,8 @@ class Shell : public i::AllStatic { static void SetUMask(const v8::FunctionCallbackInfo<v8::Value>& args); static void MakeDirectory(const v8::FunctionCallbackInfo<v8::Value>& args); static void RemoveDirectory(const v8::FunctionCallbackInfo<v8::Value>& args); + static void HostCleanupFinalizationGroup(Local<Context> context, + Local<FinalizationGroup> fg); static MaybeLocal<Promise> HostImportModuleDynamically( Local<Context> context, Local<ScriptOrModule> referrer, Local<String> specifier); @@ -493,6 +498,10 @@ class Shell : public i::AllStatic { !options.test_shell; } + static void WaitForRunningWorkers(); + static void AddRunningWorker(std::shared_ptr<Worker> worker); + static void RemoveRunningWorker(const std::shared_ptr<Worker>& worker); + private: static Global<Context> evaluation_context_; static base::OnceType quit_once_; @@ -509,7 +518,7 @@ class Shell : public i::AllStatic { static base::LazyMutex workers_mutex_; // Guards the following members. static bool allow_new_workers_; - static std::vector<Worker*> workers_; + static std::unordered_set<std::shared_ptr<Worker>> running_workers_; static std::vector<ExternalizedContents> externalized_contents_; // Multiple isolates may update this flag concurrently. |