v8/include/v8-cppgc.h
Michael Lippautz fbcaf729f2 api, cppgc-js: Allow creating a v8::CppHeap in detached state
The detached CppHeap allows for allocation without invoking garbage
collections.  Allocated bytes are reported on the first allocation
after the CppHeap has been attached to an Isolate.

States:
- Detached: Allow only allocation;
- Attached: Unified heap GCs;
- Termination GC: Require detached state;

Destruction:
- Heap::TearDown: Detach if attached;
- ~CppHeap: Detach if attached;

Bug: chromium:1056170
Change-Id: I95ce029f36a7f10392257080b6e23e13cc0fc7b8
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2672940
Commit-Queue: Michael Lippautz <mlippautz@chromium.org>
Reviewed-by: Omer Katz <omerkatz@chromium.org>
Reviewed-by: Ulan Degenbaev <ulan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#72579}
2021-02-09 09:57:52 +00:00

221 lines
7.3 KiB
C++

// 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_V8_CPPGC_H_
#define INCLUDE_V8_CPPGC_H_
#include <memory>
#include <vector>
#include "cppgc/custom-space.h"
#include "cppgc/internal/process-heap.h"
#include "cppgc/internal/write-barrier.h"
#include "cppgc/visitor.h"
#include "v8-internal.h" // NOLINT(build/include_directory)
#include "v8.h" // NOLINT(build/include_directory)
namespace cppgc {
class AllocationHandle;
class HeapHandle;
} // namespace cppgc
namespace v8 {
namespace internal {
class CppHeap;
} // namespace internal
struct V8_EXPORT CppHeapCreateParams {
std::vector<std::unique_ptr<cppgc::CustomSpaceBase>> custom_spaces;
};
/**
* A heap for allocating managed C++ objects.
*/
class V8_EXPORT CppHeap {
public:
static std::unique_ptr<CppHeap> Create(v8::Platform* platform,
const CppHeapCreateParams& params);
virtual ~CppHeap() = default;
/**
* \returns the opaque handle for allocating objects using
* `MakeGarbageCollected()`.
*/
cppgc::AllocationHandle& GetAllocationHandle();
/**
* \returns the opaque heap handle which may be used to refer to this heap in
* other APIs. Valid as long as the underlying `CppHeap` is alive.
*/
cppgc::HeapHandle& GetHeapHandle();
/**
* Terminate clears all roots and performs multiple garbage collections to
* reclaim potentially newly created objects in destructors.
*
* After this call, object allocation is prohibited.
*/
void Terminate();
private:
CppHeap() = default;
friend class internal::CppHeap;
};
class JSVisitor : public cppgc::Visitor {
public:
explicit JSVisitor(cppgc::Visitor::Key key) : cppgc::Visitor(key) {}
void Trace(const TracedReferenceBase& ref) {
if (ref.IsEmptyThreadSafe()) return;
Visit(ref);
}
protected:
using cppgc::Visitor::Visit;
virtual void Visit(const TracedReferenceBase& ref) {}
};
/**
* **DO NOT USE: Use the appropriate managed types.**
*
* Consistency helpers that aid in maintaining a consistent internal state of
* the garbage collector.
*/
class V8_EXPORT JSHeapConsistency final {
public:
using WriteBarrierParams = cppgc::internal::WriteBarrier::Params;
using WriteBarrierType = cppgc::internal::WriteBarrier::Type;
/**
* Gets the required write barrier type for a specific write.
*
* Note: Handling for C++ to JS references.
*
* \param ref The reference being written to.
* \param params Parameters that may be used for actual write barrier calls.
* Only filled if return value indicates that a write barrier is needed. The
* contents of the `params` are an implementation detail.
* \param callback Callback returning the corresponding heap handle. The
* callback is only invoked if the heap cannot otherwise be figured out. The
* callback must not allocate.
* \returns whether a write barrier is needed and which barrier to invoke.
*/
template <typename HeapHandleCallback>
static V8_INLINE WriteBarrierType
GetWriteBarrierType(const TracedReferenceBase& ref,
WriteBarrierParams& params, HeapHandleCallback callback) {
if (ref.IsEmpty()) return WriteBarrierType::kNone;
if (V8_LIKELY(!cppgc::internal::ProcessHeap::
IsAnyIncrementalOrConcurrentMarking())) {
return cppgc::internal::WriteBarrier::Type::kNone;
}
cppgc::HeapHandle& handle = callback();
if (!cppgc::subtle::HeapState::IsMarking(handle)) {
return cppgc::internal::WriteBarrier::Type::kNone;
}
params.heap = &handle;
#if V8_ENABLE_CHECKS
params.type = cppgc::internal::WriteBarrier::Type::kMarking;
#endif // !V8_ENABLE_CHECKS
return cppgc::internal::WriteBarrier::Type::kMarking;
}
/**
* Gets the required write barrier type for a specific write.
*
* Note: Handling for JS to C++ references.
*
* \param wrapper The wrapper that has been written into.
* \param wrapper_index The wrapper index in `wrapper` that has been written
* into.
* \param wrappable The value that was written.
* \param params Parameters that may be used for actual write barrier calls.
* Only filled if return value indicates that a write barrier is needed. The
* contents of the `params` are an implementation detail.
* \param callback Callback returning the corresponding heap handle. The
* callback is only invoked if the heap cannot otherwise be figured out. The
* callback must not allocate.
* \returns whether a write barrier is needed and which barrier to invoke.
*/
template <typename HeapHandleCallback>
static V8_INLINE WriteBarrierType GetWriteBarrierType(
v8::Local<v8::Object>& wrapper, int wrapper_index, const void* wrappable,
WriteBarrierParams& params, HeapHandleCallback callback) {
#if V8_ENABLE_CHECKS
CheckWrapper(wrapper, wrapper_index, wrappable);
#endif // V8_ENABLE_CHECKS
return cppgc::internal::WriteBarrier::
GetWriteBarrierTypeForExternallyReferencedObject(wrappable, params,
callback);
}
/**
* Conservative Dijkstra-style write barrier that processes an object if it
* has not yet been processed.
*
* \param params The parameters retrieved from `GetWriteBarrierType()`.
* \param ref The reference being written to.
*/
static V8_INLINE void DijkstraMarkingBarrier(const WriteBarrierParams& params,
cppgc::HeapHandle& heap_handle,
const TracedReferenceBase& ref) {
cppgc::internal::WriteBarrier::CheckParams(WriteBarrierType::kMarking,
params);
DijkstraMarkingBarrierSlow(heap_handle, ref);
}
/**
* Conservative Dijkstra-style write barrier that processes an object if it
* has not yet been processed.
*
* \param params The parameters retrieved from `GetWriteBarrierType()`.
* \param object The pointer to the object. May be an interior pointer to a
* an interface of the actual object.
*/
static V8_INLINE void DijkstraMarkingBarrier(const WriteBarrierParams& params,
cppgc::HeapHandle& heap_handle,
const void* object) {
cppgc::internal::WriteBarrier::DijkstraMarkingBarrier(params, object);
}
/**
* Generational barrier for maintaining consistency when running with multiple
* generations.
*
* \param params The parameters retrieved from `GetWriteBarrierType()`.
* \param ref The reference being written to.
*/
static V8_INLINE void GenerationalBarrier(const WriteBarrierParams& params,
const TracedReferenceBase& ref) {}
private:
JSHeapConsistency() = delete;
static void CheckWrapper(v8::Local<v8::Object>&, int, const void*);
static void DijkstraMarkingBarrierSlow(cppgc::HeapHandle&,
const TracedReferenceBase& ref);
};
} // namespace v8
namespace cppgc {
template <typename T>
struct TraceTrait<v8::TracedReference<T>> {
static void Trace(Visitor* visitor, const v8::TracedReference<T>* self) {
static_cast<v8::JSVisitor*>(visitor)->Trace(*self);
}
};
} // namespace cppgc
#endif // INCLUDE_V8_CPPGC_H_