summaryrefslogtreecommitdiff
path: root/chromium/gin
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2021-05-20 09:47:09 +0200
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2021-06-07 11:15:42 +0000
commit189d4fd8fad9e3c776873be51938cd31a42b6177 (patch)
tree6497caeff5e383937996768766ab3bb2081a40b2 /chromium/gin
parent8bc75099d364490b22f43a7ce366b366c08f4164 (diff)
downloadqtwebengine-chromium-189d4fd8fad9e3c776873be51938cd31a42b6177.tar.gz
BASELINE: Update Chromium to 90.0.4430.221
Change-Id: Iff4d9d18d2fcf1a576f3b1f453010f744a232920 Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Diffstat (limited to 'chromium/gin')
-rw-r--r--chromium/gin/OWNERS1
-rw-r--r--chromium/gin/array_buffer.cc114
-rw-r--r--chromium/gin/array_buffer.h15
-rw-r--r--chromium/gin/function_template.h5
-rw-r--r--chromium/gin/gin_features.cc16
-rw-r--r--chromium/gin/gin_features.h4
-rw-r--r--chromium/gin/modules/console.cc6
-rw-r--r--chromium/gin/public/gin_embedders.h8
-rw-r--r--chromium/gin/v8_foreground_task_runner.cc12
-rw-r--r--chromium/gin/v8_foreground_task_runner.h4
-rw-r--r--chromium/gin/v8_initializer.cc26
-rw-r--r--chromium/gin/v8_isolate_memory_dump_provider.cc8
-rw-r--r--chromium/gin/v8_platform.cc34
-rw-r--r--chromium/gin/v8_platform_unittest.cc61
-rw-r--r--chromium/gin/wrappable.h2
15 files changed, 175 insertions, 141 deletions
diff --git a/chromium/gin/OWNERS b/chromium/gin/OWNERS
index 3ac44eb8e9f..79b041ed379 100644
--- a/chromium/gin/OWNERS
+++ b/chromium/gin/OWNERS
@@ -1,3 +1,4 @@
+set noparent
jochen@chromium.org
jbroman@chromium.org
rmcilroy@chromium.org
diff --git a/chromium/gin/array_buffer.cc b/chromium/gin/array_buffer.cc
index 124c2f72a5c..210760801f1 100644
--- a/chromium/gin/array_buffer.cc
+++ b/chromium/gin/array_buffer.cc
@@ -23,12 +23,6 @@
namespace gin {
-namespace {
-
-gin::WrapperInfo g_array_buffer_wrapper_info = {gin::kEmbedderNativeGin};
-
-} // namespace
-
static_assert(V8_ARRAY_BUFFER_INTERNAL_FIELD_COUNT == 2,
"array buffers must have two internal fields");
@@ -52,113 +46,11 @@ ArrayBufferAllocator* ArrayBufferAllocator::SharedInstance() {
return instance;
}
-// ArrayBuffer::Private -------------------------------------------------------
-
-// This class exists to solve a tricky lifetime problem. The V8 API doesn't
-// want to expose a direct view into the memory behind an array buffer because
-// V8 might deallocate that memory during garbage collection. Instead, the V8
-// API forces us to externalize the buffer and take ownership of the memory.
-// In order to know when to free the memory, we need to figure out both when
-// we're done with it and when V8 is done with it.
-//
-// To determine whether we're done with the memory, every view we have into
-// the array buffer takes a reference to the ArrayBuffer::Private object that
-// actually owns the memory. To determine when V8 is done with the memory, we
-// open a weak handle to the ArrayBuffer object. When we receive the weak
-// callback, we know the object is about to be garbage collected and we can
-// drop V8's implied reference to the memory.
-//
-// The final subtlety is that we need every ArrayBuffer into the same array
-// buffer to AddRef the same ArrayBuffer::Private. To make that work, we store
-// a pointer to the ArrayBuffer::Private object in an internal field of the
-// ArrayBuffer object.
-//
-class ArrayBuffer::Private : public base::RefCounted<ArrayBuffer::Private> {
- public:
- static scoped_refptr<Private> From(v8::Isolate* isolate,
- v8::Local<v8::ArrayBuffer> array);
-
- void* buffer() const { return buffer_; }
- size_t length() const { return length_; }
-
- private:
- friend class base::RefCounted<Private>;
- using DataDeleter = void (*)(void* data, size_t length, void* info);
-
- Private(v8::Isolate* isolate, v8::Local<v8::ArrayBuffer> array);
- ~Private();
-
- static void FirstWeakCallback(const v8::WeakCallbackInfo<Private>& data);
- static void SecondWeakCallback(const v8::WeakCallbackInfo<Private>& data);
-
- v8::Global<v8::ArrayBuffer> array_buffer_;
- scoped_refptr<Private> self_reference_;
- v8::Isolate* isolate_;
- void* buffer_;
- size_t length_;
- DataDeleter deleter_;
- void* deleter_data_;
-};
-
-scoped_refptr<ArrayBuffer::Private> ArrayBuffer::Private::From(
- v8::Isolate* isolate, v8::Local<v8::ArrayBuffer> array) {
- if (array->IsExternal()) {
- CHECK_EQ(WrapperInfo::From(v8::Local<v8::Object>::Cast(array)),
- &g_array_buffer_wrapper_info)
- << "Cannot mix blink and gin ArrayBuffers";
- return base::WrapRefCounted(static_cast<Private*>(
- array->GetAlignedPointerFromInternalField(kEncodedValueIndex)));
- }
- return base::WrapRefCounted(new Private(isolate, array));
-}
-
-ArrayBuffer::Private::Private(v8::Isolate* isolate,
- v8::Local<v8::ArrayBuffer> array)
- : array_buffer_(isolate, array), isolate_(isolate) {
- // Take ownership of the array buffer.
- CHECK(!array->IsExternal());
- v8::ArrayBuffer::Contents contents = array->Externalize();
- buffer_ = contents.Data();
- length_ = contents.ByteLength();
- deleter_ = contents.Deleter();
- deleter_data_ = contents.DeleterData();
-
- array->SetAlignedPointerInInternalField(kWrapperInfoIndex,
- &g_array_buffer_wrapper_info);
- array->SetAlignedPointerInInternalField(kEncodedValueIndex, this);
-
- self_reference_ = this; // Cleared in SecondWeakCallback.
- array_buffer_.SetWeak(this, FirstWeakCallback,
- v8::WeakCallbackType::kParameter);
-}
-
-ArrayBuffer::Private::~Private() {
- deleter_(buffer_, length_, deleter_data_);
-}
-
-void ArrayBuffer::Private::FirstWeakCallback(
- const v8::WeakCallbackInfo<Private>& data) {
- Private* parameter = data.GetParameter();
- parameter->array_buffer_.Reset();
- data.SetSecondPassCallback(SecondWeakCallback);
-}
-
-void ArrayBuffer::Private::SecondWeakCallback(
- const v8::WeakCallbackInfo<Private>& data) {
- Private* parameter = data.GetParameter();
- parameter->self_reference_.reset();
-}
-
// ArrayBuffer ----------------------------------------------------------------
+ArrayBuffer::ArrayBuffer() = default;
-ArrayBuffer::ArrayBuffer() : bytes_(nullptr), num_bytes_(0) {}
-
-ArrayBuffer::ArrayBuffer(v8::Isolate* isolate,
- v8::Local<v8::ArrayBuffer> array) {
- private_ = ArrayBuffer::Private::From(isolate, array);
- bytes_ = private_->buffer();
- num_bytes_ = private_->length();
-}
+ArrayBuffer::ArrayBuffer(v8::Isolate* isolate, v8::Local<v8::ArrayBuffer> array)
+ : backing_store_(array->GetBackingStore()) {}
ArrayBuffer::~ArrayBuffer() = default;
diff --git a/chromium/gin/array_buffer.h b/chromium/gin/array_buffer.h
index 2aef366ac81..086371af29b 100644
--- a/chromium/gin/array_buffer.h
+++ b/chromium/gin/array_buffer.h
@@ -33,16 +33,15 @@ class GIN_EXPORT ArrayBuffer {
~ArrayBuffer();
ArrayBuffer& operator=(const ArrayBuffer& other);
- void* bytes() const { return bytes_; }
- size_t num_bytes() const { return num_bytes_; }
+ void* bytes() const {
+ return backing_store_ ? backing_store_->Data() : nullptr;
+ }
+ size_t num_bytes() const {
+ return backing_store_ ? backing_store_->ByteLength() : 0;
+ }
private:
- class Private;
-
- scoped_refptr<Private> private_;
- void* bytes_;
- size_t num_bytes_;
-
+ std::shared_ptr<v8::BackingStore> backing_store_;
DISALLOW_COPY(ArrayBuffer);
};
diff --git a/chromium/gin/function_template.h b/chromium/gin/function_template.h
index 3f6a1ddfead..2c13d418a09 100644
--- a/chromium/gin/function_template.h
+++ b/chromium/gin/function_template.h
@@ -248,9 +248,8 @@ v8::Local<v8::FunctionTemplate> CreateFunctionTemplate(
v8::Local<v8::FunctionTemplate> tmpl = v8::FunctionTemplate::New(
isolate, &internal::Dispatcher<Sig>::DispatchToCallback,
- ConvertToV8<v8::Local<v8::External>>(isolate,
- holder->GetHandle(isolate)));
- tmpl->RemovePrototype();
+ ConvertToV8<v8::Local<v8::External>>(isolate, holder->GetHandle(isolate)),
+ v8::Local<v8::Signature>(), 0, v8::ConstructorBehavior::kThrow);
return tmpl;
}
diff --git a/chromium/gin/gin_features.cc b/chromium/gin/gin_features.cc
index b200a04e342..a2137abed41 100644
--- a/chromium/gin/gin_features.cc
+++ b/chromium/gin/gin_features.cc
@@ -50,4 +50,20 @@ const base::Feature kV8LocalHeaps{"V8LocalHeaps",
const base::Feature kV8TurboDirectHeapAccess{"V8TurboDirectHeapAccess",
base::FEATURE_ENABLED_BY_DEFAULT};
+// Enables fallback to a breadth-first regexp engine on excessive backtracking.
+const base::Feature kV8ExperimentalRegexpEngine{
+ "V8ExperimentalRegexpEngine", base::FEATURE_ENABLED_BY_DEFAULT};
+
+// Enables experimental Turboprop compiler.
+const base::Feature kV8Turboprop{"V8Turboprop",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
+// Enables experimental Sparkplug compiler.
+const base::Feature kV8Sparkplug{"V8Sparkplug",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
+// Enables fast API calls in TurboFan.
+const base::Feature kV8TurboFastApiCalls{"V8TurboFastApiCalls",
+ base::FEATURE_DISABLED_BY_DEFAULT};
+
} // namespace features
diff --git a/chromium/gin/gin_features.h b/chromium/gin/gin_features.h
index 0e2b51c83f3..f1158d05dbb 100644
--- a/chromium/gin/gin_features.h
+++ b/chromium/gin/gin_features.h
@@ -21,6 +21,10 @@ GIN_EXPORT extern const base::Feature kV8ReduceConcurrentMarkingTasks;
GIN_EXPORT extern const base::Feature kV8NoReclaimUnmodifiedWrappers;
GIN_EXPORT extern const base::Feature kV8LocalHeaps;
GIN_EXPORT extern const base::Feature kV8TurboDirectHeapAccess;
+GIN_EXPORT extern const base::Feature kV8ExperimentalRegexpEngine;
+GIN_EXPORT extern const base::Feature kV8TurboFastApiCalls;
+GIN_EXPORT extern const base::Feature kV8Turboprop;
+GIN_EXPORT extern const base::Feature kV8Sparkplug;
} // namespace features
diff --git a/chromium/gin/modules/console.cc b/chromium/gin/modules/console.cc
index 8786392b9e6..7e3087fb982 100644
--- a/chromium/gin/modules/console.cc
+++ b/chromium/gin/modules/console.cc
@@ -29,9 +29,9 @@ void Log(const v8::FunctionCallbackInfo<v8::Value>& info) {
// static
void Console::Register(v8::Isolate* isolate,
v8::Local<v8::ObjectTemplate> templ) {
- v8::Local<v8::FunctionTemplate> log_templ =
- v8::FunctionTemplate::New(isolate, Log);
- log_templ->RemovePrototype();
+ v8::Local<v8::FunctionTemplate> log_templ = v8::FunctionTemplate::New(
+ isolate, Log, v8::Local<v8::Value>(), v8::Local<v8::Signature>(), 0,
+ v8::ConstructorBehavior::kThrow);
templ->Set(StringToSymbol(isolate, "log"), log_templ);
}
diff --git a/chromium/gin/public/gin_embedders.h b/chromium/gin/public/gin_embedders.h
index 30f48a6c859..e88cc0a555b 100644
--- a/chromium/gin/public/gin_embedders.h
+++ b/chromium/gin/public/gin_embedders.h
@@ -5,13 +5,17 @@
#ifndef GIN_PUBLIC_GIN_EMBEDDERS_H_
#define GIN_PUBLIC_GIN_EMBEDDERS_H_
+#include <cstdint>
+
namespace gin {
// The GinEmbedder is used to identify the owner of embedder data stored on
// v8 objects, and is used as in index into the embedder data slots of a
// v8::Isolate.
-
-enum GinEmbedder {
+//
+// GinEmbedder is using uint16_t as underlying storage as V8 requires that
+// external pointers in embedder fields are at least 2-byte-aligned.
+enum GinEmbedder : uint16_t {
kEmbedderNativeGin,
kEmbedderBlink,
kEmbedderPDFium,
diff --git a/chromium/gin/v8_foreground_task_runner.cc b/chromium/gin/v8_foreground_task_runner.cc
index f0b1209babe..4d93e27b64b 100644
--- a/chromium/gin/v8_foreground_task_runner.cc
+++ b/chromium/gin/v8_foreground_task_runner.cc
@@ -37,6 +37,14 @@ void V8ForegroundTaskRunner::PostDelayedTask(std::unique_ptr<v8::Task> task,
base::TimeDelta::FromSecondsD(delay_in_seconds));
}
+void V8ForegroundTaskRunner::PostNonNestableDelayedTask(
+ std::unique_ptr<v8::Task> task,
+ double delay_in_seconds) {
+ task_runner_->PostNonNestableDelayedTask(
+ FROM_HERE, base::BindOnce(&v8::Task::Run, std::move(task)),
+ base::TimeDelta::FromSecondsD(delay_in_seconds));
+}
+
void V8ForegroundTaskRunner::PostIdleTask(std::unique_ptr<v8::IdleTask> task) {
DCHECK(IdleTasksEnabled());
idle_task_runner()->PostIdleTask(std::move(task));
@@ -46,4 +54,8 @@ bool V8ForegroundTaskRunner::NonNestableTasksEnabled() const {
return true;
}
+bool V8ForegroundTaskRunner::NonNestableDelayedTasksEnabled() const {
+ return true;
+}
+
} // namespace gin
diff --git a/chromium/gin/v8_foreground_task_runner.h b/chromium/gin/v8_foreground_task_runner.h
index 62e4f3ad450..2f8a6ffebf3 100644
--- a/chromium/gin/v8_foreground_task_runner.h
+++ b/chromium/gin/v8_foreground_task_runner.h
@@ -29,9 +29,13 @@ class V8ForegroundTaskRunner : public V8ForegroundTaskRunnerBase {
void PostDelayedTask(std::unique_ptr<v8::Task> task,
double delay_in_seconds) override;
+ void PostNonNestableDelayedTask(std::unique_ptr<v8::Task> task,
+ double delay_in_seconds) override;
+
void PostIdleTask(std::unique_ptr<v8::IdleTask> task) override;
bool NonNestableTasksEnabled() const override;
+ bool NonNestableDelayedTasksEnabled() const override;
private:
scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
diff --git a/chromium/gin/v8_initializer.cc b/chromium/gin/v8_initializer.cc
index 4174fd98f3a..e9cc71b9684 100644
--- a/chromium/gin/v8_initializer.cc
+++ b/chromium/gin/v8_initializer.cc
@@ -288,6 +288,32 @@ void V8Initializer::Initialize(IsolateHolder::ScriptMode mode) {
v8::V8::SetFlagsFromString(no_direct_access, sizeof(no_direct_access) - 1);
}
+ if (!base::FeatureList::IsEnabled(features::kV8ExperimentalRegexpEngine)) {
+ // The --enable-experimental-regexp-engine-on-excessive-backtracks flag is
+ // enabled by default, so we need to explicitly disable it if
+ // kV8ExperimentalRegexpEngine is disabled.
+ static constexpr char no_experimental_regexp_engine[] =
+ "--no-enable-experimental-regexp-engine-on-excessive-backtracks";
+ v8::V8::SetFlagsFromString(no_experimental_regexp_engine,
+ sizeof(no_experimental_regexp_engine) - 1);
+ }
+
+ if (base::FeatureList::IsEnabled(features::kV8TurboFastApiCalls)) {
+ static const char turbo_fast_api_calls[] = "--turbo-fast-api-calls";
+ v8::V8::SetFlagsFromString(turbo_fast_api_calls,
+ sizeof(turbo_fast_api_calls) - 1);
+ }
+
+ if (base::FeatureList::IsEnabled(features::kV8Turboprop)) {
+ static const char turboprop[] = "--turboprop";
+ v8::V8::SetFlagsFromString(turboprop, sizeof(turboprop) - 1);
+ }
+
+ if (base::FeatureList::IsEnabled(features::kV8Sparkplug)) {
+ static const char sparkplug[] = "--sparkplug";
+ v8::V8::SetFlagsFromString(sparkplug, sizeof(sparkplug) - 1);
+ }
+
if (IsolateHolder::kStrictMode == mode) {
static const char use_strict[] = "--use_strict";
v8::V8::SetFlagsFromString(use_strict, sizeof(use_strict) - 1);
diff --git a/chromium/gin/v8_isolate_memory_dump_provider.cc b/chromium/gin/v8_isolate_memory_dump_provider.cc
index 8df3b0f5e86..3f1f9954af8 100644
--- a/chromium/gin/v8_isolate_memory_dump_provider.cc
+++ b/chromium/gin/v8_isolate_memory_dump_provider.cc
@@ -264,6 +264,14 @@ void V8IsolateMemoryDumpProvider::DumpHeapStatistics(
base::trace_event::MemoryAllocatorDump::kNameSize,
base::trace_event::MemoryAllocatorDump::kUnitsBytes,
heap_statistics.total_global_handles_size());
+ global_handles_dump->AddScalar(
+ "allocated_objects_size",
+ base::trace_event::MemoryAllocatorDump::kUnitsBytes,
+ heap_statistics.used_global_handles_size());
+ if (system_allocator_name) {
+ process_memory_dump->AddSuballocation(global_handles_dump->guid(),
+ system_allocator_name);
+ }
// Dump object statistics only for detailed dumps.
if (args.level_of_detail !=
diff --git a/chromium/gin/v8_platform.cc b/chromium/gin/v8_platform.cc
index 68415704fd7..71b0ec4a05d 100644
--- a/chromium/gin/v8_platform.cc
+++ b/chromium/gin/v8_platform.cc
@@ -22,6 +22,7 @@
#include "base/task/task_traits.h"
#include "base/task/thread_pool/thread_pool_instance.h"
#include "base/trace_event/trace_event.h"
+#include "base/tracing_buildflags.h"
#include "build/build_config.h"
#include "gin/per_isolate_data.h"
@@ -245,7 +246,8 @@ class PageAllocator : public v8::PageAllocator {
// On Windows, we can only de-commit the trailing pages. FreePages() will
// still free all pages in the region including the released tail, so it's
// safe to just decommit the tail.
- base::DecommitSystemPages(release_base, release_size);
+ base::DecommitSystemPages(release_base, release_size,
+ base::PageUpdatePermissions);
#else
#error Unsupported platform
#endif
@@ -257,7 +259,12 @@ class PageAllocator : public v8::PageAllocator {
Permission permissions) override {
// If V8 sets permissions to none, we can discard the memory.
if (permissions == v8::PageAllocator::Permission::kNoAccess) {
- base::DecommitSystemPages(address, length);
+ // Use PageKeepPermissionsIfPossible as an optimization, to avoid perf
+ // regression (see crrev.com/c/2563038 for details). This may cause the
+ // memory region to still be accessible on certain platforms, but at least
+ // the physical pages will be discarded.
+ base::DecommitSystemPages(address, length,
+ base::PageKeepPermissionsIfPossible);
return true;
} else {
return base::TrySetSystemPagesAccess(address, length,
@@ -298,8 +305,7 @@ class JobDelegateImpl : public v8::JobDelegate {
class JobHandleImpl : public v8::JobHandle {
public:
- JobHandleImpl(base::JobHandle handle, std::unique_ptr<v8::JobTask> job_task)
- : handle_(std::move(handle)), job_task_(std::move(job_task)) {}
+ explicit JobHandleImpl(base::JobHandle handle) : handle_(std::move(handle)) {}
~JobHandleImpl() override = default;
JobHandleImpl(const JobHandleImpl&) = delete;
@@ -316,8 +322,8 @@ class JobHandleImpl : public v8::JobHandle {
void Join() override { handle_.Join(); }
void Cancel() override { handle_.Cancel(); }
void CancelAndDetach() override { handle_.CancelAndDetach(); }
- bool IsCompleted() override { return handle_.IsCompleted(); }
- bool IsRunning() override { return !!handle_; }
+ bool IsActive() override { return handle_.IsActive(); }
+ bool IsValid() override { return !!handle_; }
private:
static base::TaskPriority ToBaseTaskPriority(v8::TaskPriority priority) {
@@ -332,7 +338,6 @@ class JobHandleImpl : public v8::JobHandle {
}
base::JobHandle handle_;
- std::unique_ptr<v8::JobTask> job_task_;
};
} // namespace
@@ -363,6 +368,7 @@ class V8Platform::TracingControllerImpl : public v8::TracingController {
~TracingControllerImpl() override = default;
// TracingController implementation.
+#if !BUILDFLAG(USE_PERFETTO_CLIENT_LIBRARY)
const uint8_t* GetCategoryGroupEnabled(const char* name) override {
return TRACE_EVENT_API_GET_CATEGORY_GROUP_ENABLED(name);
}
@@ -430,6 +436,7 @@ class V8Platform::TracingControllerImpl : public v8::TracingController {
TRACE_EVENT_API_UPDATE_TRACE_EVENT_DURATION(category_enabled_flag, name,
traceEventHandle);
}
+#endif // !BUILDFLAG(USE_PERFETTO_CLIENT_LIBRARY)
void AddTraceStateObserver(TraceStateObserver* observer) override {
g_trace_state_dispatcher.Get().AddObserver(observer);
}
@@ -522,22 +529,25 @@ std::unique_ptr<v8::JobHandle> V8Platform::PostJob(
task_traits = kBlockingTaskTraits;
break;
}
+ // Ownership of |job_task| is assumed by |worker_task|, while
+ // |max_concurrency_callback| uses an unretained pointer.
+ auto* job_task_ptr = job_task.get();
auto handle =
base::PostJob(FROM_HERE, task_traits,
base::BindRepeating(
- [](v8::JobTask* job_task, base::JobDelegate* delegate) {
+ [](const std::unique_ptr<v8::JobTask>& job_task,
+ base::JobDelegate* delegate) {
JobDelegateImpl delegate_impl(delegate);
job_task->Run(&delegate_impl);
},
- base::Unretained(job_task.get())),
+ std::move(job_task)),
base::BindRepeating(
[](v8::JobTask* job_task, size_t worker_count) {
return job_task->GetMaxConcurrency(worker_count);
},
- base::Unretained(job_task.get())));
+ base::Unretained(job_task_ptr)));
- return std::make_unique<JobHandleImpl>(std::move(handle),
- std::move(job_task));
+ return std::make_unique<JobHandleImpl>(std::move(handle));
}
bool V8Platform::IdleTasksEnabled(v8::Isolate* isolate) {
diff --git a/chromium/gin/v8_platform_unittest.cc b/chromium/gin/v8_platform_unittest.cc
index 8dbfbd4342e..332e0f7995c 100644
--- a/chromium/gin/v8_platform_unittest.cc
+++ b/chromium/gin/v8_platform_unittest.cc
@@ -6,7 +6,9 @@
#include <atomic>
+#include "base/barrier_closure.h"
#include "base/test/task_environment.h"
+#include "base/test/test_waitable_event.h"
#include "base/trace_event/trace_event.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -84,10 +86,65 @@ TEST(V8PlatformTest, PostJobSimple) {
auto handle =
V8Platform::Get()->PostJob(v8::TaskPriority::kUserVisible,
std::make_unique<Task>(&num_tasks_to_run));
- EXPECT_TRUE(handle->IsRunning());
+ EXPECT_TRUE(handle->IsValid());
handle->Join();
- EXPECT_FALSE(handle->IsRunning());
+ EXPECT_FALSE(handle->IsValid());
DCHECK_EQ(num_tasks_to_run, 0U);
}
+// Tests that JobTask's lifetime is extended beyond job handle, until no
+// references are left; and is gracefully destroyed.
+TEST(V8PlatformTest, PostJobLifetime) {
+ std::atomic_size_t num_tasks_to_run(4);
+
+ base::TestWaitableEvent threads_running;
+ base::TestWaitableEvent threads_continue;
+ base::RepeatingClosure threads_running_barrier = base::BarrierClosure(
+ num_tasks_to_run,
+ BindOnce(&base::TestWaitableEvent::Signal, Unretained(&threads_running)));
+
+ class Task : public v8::JobTask {
+ public:
+ explicit Task(std::atomic_size_t* num_tasks_to_run,
+ base::RepeatingClosure threads_running_barrier,
+ base::TestWaitableEvent* threads_continue)
+ : num_tasks_to_run_(num_tasks_to_run),
+ threads_running_barrier_(std::move(threads_running_barrier)),
+ threads_continue_(threads_continue) {}
+ ~Task() override {
+ // This should only be destroyed once all workers returned.
+ EXPECT_EQ(*num_tasks_to_run_, 0U);
+ }
+
+ void Run(v8::JobDelegate* delegate) override {
+ threads_running_barrier_.Run();
+ threads_continue_->Wait();
+ --(*num_tasks_to_run_);
+ }
+
+ size_t GetMaxConcurrency(size_t /* worker_count*/) const override {
+ return *num_tasks_to_run_;
+ }
+
+ std::atomic_size_t* num_tasks_to_run_;
+ base::RepeatingClosure threads_running_barrier_;
+ base::TestWaitableEvent* threads_continue_;
+ };
+
+ base::test::TaskEnvironment task_environment;
+
+ auto handle = V8Platform::Get()->PostJob(
+ v8::TaskPriority::kUserVisible,
+ std::make_unique<Task>(&num_tasks_to_run,
+ std::move(threads_running_barrier),
+ &threads_continue));
+ EXPECT_TRUE(handle->IsValid());
+ threads_running.Wait();
+ handle->CancelAndDetach();
+ handle.reset();
+
+ // Release workers and let the job get destroyed.
+ threads_continue.Signal();
+}
+
} // namespace gin
diff --git a/chromium/gin/wrappable.h b/chromium/gin/wrappable.h
index d558ffb6d68..f9b7b938cb7 100644
--- a/chromium/gin/wrappable.h
+++ b/chromium/gin/wrappable.h
@@ -120,6 +120,8 @@ struct Converter<T*,
typename std::enable_if<
std::is_convertible<T*, WrappableBase*>::value>::type> {
static v8::MaybeLocal<v8::Value> ToV8(v8::Isolate* isolate, T* val) {
+ if (val == nullptr)
+ return v8::Null(isolate);
v8::Local<v8::Object> wrapper;
if (!val->GetWrapper(isolate).ToLocal(&wrapper))
return v8::MaybeLocal<v8::Value>();