cppgc: Add DefaultPlatform and standalone sample
Standalone sample doesn't use libplatform for default platform implementation. This is needed for Oilpan GitHub mirror, which won't contain libplatform. Bug: v8:10724 Change-Id: I2e20ad157263a5073d0ba9ae8a2e211b2fcb35ed Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2310362 Reviewed-by: Ulan Degenbaev <ulan@chromium.org> Reviewed-by: Yang Guo <yangguo@chromium.org> Reviewed-by: Michael Lippautz <mlippautz@chromium.org> Reviewed-by: Omer Katz <omerkatz@chromium.org> Commit-Queue: Anton Bikineev <bikineev@chromium.org> Cr-Commit-Position: refs/heads/master@{#69016}
This commit is contained in:
parent
938ed34159
commit
e68ff8e2ea
16
BUILD.gn
16
BUILD.gn
@ -4213,6 +4213,7 @@ v8_source_set("cppgc_base") {
|
||||
"include/cppgc/allocation.h",
|
||||
"include/cppgc/common.h",
|
||||
"include/cppgc/custom-space.h",
|
||||
"include/cppgc/default-platform.h",
|
||||
"include/cppgc/garbage-collected.h",
|
||||
"include/cppgc/heap.h",
|
||||
"include/cppgc/internal/api-constants.h",
|
||||
@ -4226,7 +4227,6 @@ v8_source_set("cppgc_base") {
|
||||
"include/cppgc/internal/process-heap.h",
|
||||
"include/cppgc/internal/write-barrier.h",
|
||||
"include/cppgc/liveness-broker.h",
|
||||
"include/cppgc/liveness-broker.h",
|
||||
"include/cppgc/macros.h",
|
||||
"include/cppgc/member.h",
|
||||
"include/cppgc/persistent.h",
|
||||
@ -4238,6 +4238,7 @@ v8_source_set("cppgc_base") {
|
||||
"include/cppgc/visitor.h",
|
||||
"include/v8config.h",
|
||||
"src/heap/cppgc/allocation.cc",
|
||||
"src/heap/cppgc/default-platform.cc",
|
||||
"src/heap/cppgc/free-list.cc",
|
||||
"src/heap/cppgc/free-list.h",
|
||||
"src/heap/cppgc/garbage-collector.h",
|
||||
@ -4839,6 +4840,19 @@ v8_executable("cppgc_for_v8_embedders") {
|
||||
]
|
||||
}
|
||||
|
||||
v8_executable("cppgc_standalone") {
|
||||
sources = [ "samples/cppgc/cppgc-standalone.cc" ]
|
||||
|
||||
configs = [
|
||||
# Note: don't use :internal_config here because this target will get
|
||||
# the :external_config applied to it by virtue of depending on :cppgc, and
|
||||
# you can't have both applied to the same target.
|
||||
":internal_config_base",
|
||||
]
|
||||
|
||||
deps = [ ":cppgc" ]
|
||||
}
|
||||
|
||||
template("v8_fuzzer") {
|
||||
name = target_name
|
||||
forward_variables_from(invoker, "*")
|
||||
|
76
include/cppgc/default-platform.h
Normal file
76
include/cppgc/default-platform.h
Normal file
@ -0,0 +1,76 @@
|
||||
// Copyright 2020 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#ifndef INCLUDE_CPPGC_DEFAULT_PLATFORM_H_
|
||||
#define INCLUDE_CPPGC_DEFAULT_PLATFORM_H_
|
||||
|
||||
#include <memory>
|
||||
#include <thread> // NOLINT(build/c++11)
|
||||
#include <vector>
|
||||
|
||||
#include "cppgc/platform.h"
|
||||
#include "v8config.h" // NOLINT(build/include_directory)
|
||||
|
||||
namespace cppgc {
|
||||
|
||||
/**
|
||||
* Default task runner implementation. Keep posted tasks in a list that can be
|
||||
* processed by calling RunSingleTask() or RunUntilIdle().
|
||||
*/
|
||||
class V8_EXPORT DefaultTaskRunner final : public cppgc::TaskRunner {
|
||||
public:
|
||||
DefaultTaskRunner() = default;
|
||||
|
||||
DefaultTaskRunner(const DefaultTaskRunner&) = delete;
|
||||
DefaultTaskRunner& operator=(const DefaultTaskRunner&) = delete;
|
||||
|
||||
void PostTask(std::unique_ptr<cppgc::Task> task) override;
|
||||
void PostNonNestableTask(std::unique_ptr<cppgc::Task> task) override;
|
||||
void PostDelayedTask(std::unique_ptr<cppgc::Task> task, double) override;
|
||||
void PostNonNestableDelayedTask(std::unique_ptr<cppgc::Task> task,
|
||||
double) override;
|
||||
|
||||
void PostIdleTask(std::unique_ptr<cppgc::IdleTask> task) override;
|
||||
bool IdleTasksEnabled() override { return true; }
|
||||
|
||||
bool RunSingleTask();
|
||||
bool RunSingleIdleTask(double duration_in_seconds);
|
||||
|
||||
void RunUntilIdle();
|
||||
|
||||
private:
|
||||
std::vector<std::unique_ptr<cppgc::Task>> tasks_;
|
||||
std::vector<std::unique_ptr<cppgc::IdleTask>> idle_tasks_;
|
||||
};
|
||||
|
||||
/**
|
||||
* Default platform implementation that uses std::thread for spawning job tasks.
|
||||
*/
|
||||
class V8_EXPORT DefaultPlatform final : public Platform {
|
||||
public:
|
||||
DefaultPlatform();
|
||||
~DefaultPlatform() noexcept override;
|
||||
|
||||
cppgc::PageAllocator* GetPageAllocator() final;
|
||||
|
||||
double MonotonicallyIncreasingTime() final;
|
||||
|
||||
std::shared_ptr<cppgc::TaskRunner> GetForegroundTaskRunner() final;
|
||||
|
||||
std::unique_ptr<cppgc::JobHandle> PostJob(
|
||||
cppgc::TaskPriority priority,
|
||||
std::unique_ptr<cppgc::JobTask> job_task) final;
|
||||
|
||||
void WaitAllForegroundTasks();
|
||||
void WaitAllBackgroundTasks();
|
||||
|
||||
private:
|
||||
std::unique_ptr<PageAllocator> page_allocator_;
|
||||
std::shared_ptr<DefaultTaskRunner> foreground_task_runner_;
|
||||
std::vector<std::shared_ptr<std::thread>> job_threads_;
|
||||
};
|
||||
|
||||
} // namespace cppgc
|
||||
|
||||
#endif // INCLUDE_CPPGC_DEFAULT_PLATFORM_H_
|
@ -14,6 +14,7 @@ namespace cppgc {
|
||||
// V8-specific.
|
||||
using IdleTask = v8::IdleTask;
|
||||
using JobHandle = v8::JobHandle;
|
||||
using JobDelegate = v8::JobDelegate;
|
||||
using JobTask = v8::JobTask;
|
||||
using PageAllocator = v8::PageAllocator;
|
||||
using Task = v8::Task;
|
||||
|
64
samples/cppgc/cppgc-standalone.cc
Normal file
64
samples/cppgc/cppgc-standalone.cc
Normal file
@ -0,0 +1,64 @@
|
||||
// Copyright 2020 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include <cppgc/allocation.h>
|
||||
#include <cppgc/default-platform.h>
|
||||
#include <cppgc/garbage-collected.h>
|
||||
#include <cppgc/heap.h>
|
||||
#include <cppgc/member.h>
|
||||
#include <cppgc/visitor.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
/**
|
||||
* This sample program shows how to set up a stand-alone cppgc heap.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Simple string rope to illustrate allocation and garbage collection below.
|
||||
* The rope keeps the next parts alive via regular managed reference.
|
||||
*/
|
||||
class Rope final : public cppgc::GarbageCollected<Rope> {
|
||||
public:
|
||||
explicit Rope(std::string part, Rope* next = nullptr)
|
||||
: part_(part), next_(next) {}
|
||||
|
||||
void Trace(cppgc::Visitor* visitor) const { visitor->Trace(next_); }
|
||||
|
||||
private:
|
||||
std::string part_;
|
||||
cppgc::Member<Rope> next_;
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& os, const Rope& rope) {
|
||||
os << rope.part_;
|
||||
if (rope.next_) {
|
||||
os << *rope.next_;
|
||||
}
|
||||
return os;
|
||||
}
|
||||
};
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
// Create a default platform that is used by cppgc::Heap for execution and
|
||||
// backend allocation.
|
||||
auto cppgc_platform = std::make_shared<cppgc::DefaultPlatform>();
|
||||
// Initialize the process. This must happen before any
|
||||
// cppgc::Heap::Create() calls.
|
||||
cppgc::InitializeProcess(cppgc_platform->GetPageAllocator());
|
||||
// Create a managed heap.
|
||||
std::unique_ptr<cppgc::Heap> heap = cppgc::Heap::Create(cppgc_platform);
|
||||
// Allocate a string rope on the managed heap.
|
||||
auto* greeting = cppgc::MakeGarbageCollected<Rope>(
|
||||
heap->GetAllocationHandle(), "Hello ",
|
||||
cppgc::MakeGarbageCollected<Rope>(heap->GetAllocationHandle(), "World!"));
|
||||
// Manually trigger garbage collection. The object greeting is held alive
|
||||
// through conservative stack scanning.
|
||||
heap->ForceGarbageCollectionSlow("CppGC stand-alone example", "Testing");
|
||||
std::cout << *greeting << std::endl;
|
||||
// Gracefully shutdown the process.
|
||||
cppgc::ShutdownProcess();
|
||||
return 0;
|
||||
}
|
133
src/heap/cppgc/default-platform.cc
Normal file
133
src/heap/cppgc/default-platform.cc
Normal file
@ -0,0 +1,133 @@
|
||||
// Copyright 2020 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
#include "include/cppgc/default-platform.h"
|
||||
|
||||
#include <chrono> // NOLINT(build/c++11)
|
||||
#include <thread> // NOLINT(build/c++11)
|
||||
|
||||
#include "src/base/page-allocator.h"
|
||||
|
||||
namespace cppgc {
|
||||
|
||||
namespace {
|
||||
|
||||
// Simple implementation of JobTask based on std::thread.
|
||||
class DefaultJobHandle : public JobHandle {
|
||||
public:
|
||||
explicit DefaultJobHandle(std::shared_ptr<std::thread> thread)
|
||||
: thread_(std::move(thread)) {}
|
||||
|
||||
void NotifyConcurrencyIncrease() override {}
|
||||
void Join() override {
|
||||
if (thread_->joinable()) thread_->join();
|
||||
}
|
||||
void Cancel() override { Join(); }
|
||||
bool IsRunning() override { return thread_->joinable(); }
|
||||
|
||||
private:
|
||||
std::shared_ptr<std::thread> thread_;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
void DefaultTaskRunner::PostTask(std::unique_ptr<cppgc::Task> task) {
|
||||
tasks_.push_back(std::move(task));
|
||||
}
|
||||
|
||||
void DefaultTaskRunner::PostNonNestableTask(std::unique_ptr<cppgc::Task> task) {
|
||||
PostTask(std::move(task));
|
||||
}
|
||||
|
||||
void DefaultTaskRunner::PostDelayedTask(std::unique_ptr<cppgc::Task> task,
|
||||
double) {
|
||||
PostTask(std::move(task));
|
||||
}
|
||||
|
||||
void DefaultTaskRunner::PostNonNestableDelayedTask(
|
||||
std::unique_ptr<cppgc::Task> task, double) {
|
||||
PostTask(std::move(task));
|
||||
}
|
||||
|
||||
void DefaultTaskRunner::PostIdleTask(std::unique_ptr<cppgc::IdleTask> task) {
|
||||
idle_tasks_.push_back(std::move(task));
|
||||
}
|
||||
|
||||
bool DefaultTaskRunner::RunSingleTask() {
|
||||
if (!tasks_.size()) return false;
|
||||
|
||||
tasks_.back()->Run();
|
||||
tasks_.pop_back();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DefaultTaskRunner::RunSingleIdleTask(double deadline_in_seconds) {
|
||||
if (!idle_tasks_.size()) return false;
|
||||
|
||||
idle_tasks_.back()->Run(deadline_in_seconds);
|
||||
idle_tasks_.pop_back();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void DefaultTaskRunner::RunUntilIdle() {
|
||||
for (auto& task : tasks_) {
|
||||
task->Run();
|
||||
}
|
||||
tasks_.clear();
|
||||
|
||||
for (auto& task : idle_tasks_) {
|
||||
task->Run(std::numeric_limits<double>::infinity());
|
||||
}
|
||||
idle_tasks_.clear();
|
||||
}
|
||||
|
||||
DefaultPlatform::DefaultPlatform()
|
||||
: page_allocator_(std::make_unique<v8::base::PageAllocator>()),
|
||||
foreground_task_runner_(std::make_shared<DefaultTaskRunner>()) {}
|
||||
|
||||
DefaultPlatform::~DefaultPlatform() noexcept { WaitAllBackgroundTasks(); }
|
||||
|
||||
cppgc::PageAllocator* DefaultPlatform::GetPageAllocator() {
|
||||
return page_allocator_.get();
|
||||
}
|
||||
|
||||
double DefaultPlatform::MonotonicallyIncreasingTime() {
|
||||
return std::chrono::duration<double>(
|
||||
std::chrono::high_resolution_clock::now().time_since_epoch())
|
||||
.count();
|
||||
}
|
||||
|
||||
std::shared_ptr<cppgc::TaskRunner> DefaultPlatform::GetForegroundTaskRunner() {
|
||||
return foreground_task_runner_;
|
||||
}
|
||||
|
||||
std::unique_ptr<cppgc::JobHandle> DefaultPlatform::PostJob(
|
||||
cppgc::TaskPriority priority, std::unique_ptr<cppgc::JobTask> job_task) {
|
||||
auto thread = std::make_shared<std::thread>([task = std::move(job_task)] {
|
||||
class SimpleDelegate final : public cppgc::JobDelegate {
|
||||
public:
|
||||
bool ShouldYield() override { return false; }
|
||||
void NotifyConcurrencyIncrease() override {}
|
||||
} delegate;
|
||||
|
||||
if (task) task->Run(&delegate);
|
||||
});
|
||||
job_threads_.push_back(thread);
|
||||
return std::make_unique<DefaultJobHandle>(std::move(thread));
|
||||
}
|
||||
|
||||
void DefaultPlatform::WaitAllForegroundTasks() {
|
||||
foreground_task_runner_->RunUntilIdle();
|
||||
}
|
||||
|
||||
void DefaultPlatform::WaitAllBackgroundTasks() {
|
||||
for (auto& thread : job_threads_) {
|
||||
thread->join();
|
||||
}
|
||||
job_threads_.clear();
|
||||
}
|
||||
|
||||
} // namespace cppgc
|
Loading…
Reference in New Issue
Block a user