Commit edef7f13 authored by Michael Lippautz's avatar Michael Lippautz Committed by Commit Bot

[api,global-handle] Introduce TracedGlobal::SetFinalizationCallback

Introduce a way to set a custom finalization callback that can be used
to signal and set up destruction of embedder memory.

Bug: chromium:923361
Change-Id: Ifc62ebd534aba3b02511c74b59161ec3edc0ee0d
Reviewed-on: https://chromium-review.googlesource.com/c/1452447
Commit-Queue: Michael Lippautz <mlippautz@chromium.org>
Reviewed-by: 's avatarUlan Degenbaev <ulan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#59381}
parent 8408dbaf
......@@ -941,6 +941,19 @@ class V8_EXPORT TracedGlobal {
*/
V8_INLINE uint16_t WrapperClassId() const;
/**
* Adds a finalization callback to the handle. The type of this callback is
* similar to WeakCallbackType::kInternalFields, i.e., it will pass the
* parameter and the first two internal fields of the object.
*
* The callback is then supposed to reset the handle in the callback. No
* further V8 API may be called in this callback. In case additional work
* involving V8 needs to be done, a second callback can be scheduled using
* WeakCallbackInfo<void>::SetSecondPassCallback.
*/
V8_INLINE void SetFinalizationCallback(
void* parameter, WeakCallbackInfo<void>::Callback callback);
private:
V8_INLINE static T* New(Isolate* isolate, T* that, T** slot);
......@@ -8681,6 +8694,9 @@ class V8_EXPORT V8 {
WeakCallbackType type);
static void MakeWeak(internal::Address** location_addr);
static void* ClearWeak(internal::Address* location);
static void SetFinalizationCallbackTraced(
internal::Address* location, void* parameter,
WeakCallbackInfo<void>::Callback callback);
static void AnnotateStrongRetainer(internal::Address* location,
const char* label);
static Value* Eternalize(Isolate* isolate, Value* handle);
......@@ -9858,6 +9874,13 @@ uint16_t TracedGlobal<T>::WrapperClassId() const {
return *reinterpret_cast<uint16_t*>(addr);
}
template <class T>
void TracedGlobal<T>::SetFinalizationCallback(
void* parameter, typename WeakCallbackInfo<void>::Callback callback) {
V8::SetFinalizationCallbackTraced(
reinterpret_cast<internal::Address*>(this->val_), parameter, callback);
}
template <typename T>
ReturnValue<T>::ReturnValue(internal::Address* slot) : value_(slot) {}
......
......@@ -1074,6 +1074,13 @@ void V8::DisposeTracedGlobal(internal::Address* location) {
i::GlobalHandles::DestroyTraced(location);
}
void V8::SetFinalizationCallbackTraced(
internal::Address* location, void* parameter,
WeakCallbackInfo<void>::Callback callback) {
i::GlobalHandles::SetFinalizationCallbackForTraced(location, parameter,
callback);
}
Value* V8::Eternalize(Isolate* v8_isolate, Value* value) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(v8_isolate);
i::Object object = *Utils::OpenHandle(value);
......
This diff is collapsed.
......@@ -6,6 +6,7 @@
#define V8_GLOBAL_HANDLES_H_
#include <type_traits>
#include <utility>
#include <vector>
#include "include/v8.h"
......@@ -43,17 +44,16 @@ class GlobalHandles final {
template <class NodeType>
class NodeBlock;
// Move a global handle.
static void MoveGlobal(Address** from, Address** to);
static void MoveTracedGlobal(Address** from, Address** to);
//
// API for regular handles.
//
// Destroy a global handle.
static void Destroy(Address* location);
static void DestroyTraced(Address* location);
static void MoveGlobal(Address** from, Address** to);
// Copy a global handle.
static Handle<Object> CopyGlobal(Address* location);
static void Destroy(Address* location);
// Make the global handle weak and set the callback parameter for the
// handle. When the garbage collector recognizes that only weak global
// handles point to an object the callback function is invoked (for each
......@@ -66,7 +66,6 @@ class GlobalHandles final {
static void MakeWeak(Address* location, void* parameter,
WeakCallbackInfo<void>::Callback weak_callback,
v8::WeakCallbackType type);
static void MakeWeak(Address** location_addr);
static void AnnotateStrongRetainer(Address* location, const char* label);
......@@ -80,6 +79,16 @@ class GlobalHandles final {
// Tells whether global handle is weak.
static bool IsWeak(Address* location);
//
// API for traced handles.
//
static void MoveTracedGlobal(Address** from, Address** to);
static void DestroyTraced(Address* location);
static void SetFinalizationCallbackForTraced(
Address* location, void* parameter,
WeakCallbackInfo<void>::Callback callback);
explicit GlobalHandles(Isolate* isolate);
~GlobalHandles();
......@@ -195,6 +204,10 @@ class GlobalHandles final {
size_t PostScavengeProcessing(unsigned post_processing_count);
size_t PostMarkSweepProcessing(unsigned post_processing_count);
template <typename T>
size_t InvokeFirstPassWeakCallbacks(
std::vector<std::pair<T*, PendingPhantomCallback>>* pending);
template <typename T>
void UpdateAndCompactListOfNewSpaceNode(std::vector<T*>* node_list);
void UpdateListOfNewSpaceNodes();
......@@ -216,7 +229,10 @@ class GlobalHandles final {
size_t handles_count_ = 0;
size_t number_of_phantom_handle_resets_ = 0;
std::vector<PendingPhantomCallback> pending_phantom_callbacks_;
std::vector<std::pair<Node*, PendingPhantomCallback>>
regular_pending_phantom_callbacks_;
std::vector<std::pair<TracedNode*, PendingPhantomCallback>>
traced_pending_phantom_callbacks_;
std::vector<PendingPhantomCallback> second_pass_callbacks_;
bool second_pass_callbacks_task_posted_ = false;
......@@ -229,22 +245,23 @@ class GlobalHandles final {
class GlobalHandles::PendingPhantomCallback final {
public:
typedef v8::WeakCallbackInfo<void> Data;
enum InvocationType { kFirstPass, kSecondPass };
PendingPhantomCallback(
Node* node, Data::Callback callback, void* parameter,
Data::Callback callback, void* parameter,
void* embedder_fields[v8::kEmbedderFieldsInWeakCallback])
: node_(node), callback_(callback), parameter_(parameter) {
: callback_(callback), parameter_(parameter) {
for (int i = 0; i < v8::kEmbedderFieldsInWeakCallback; ++i) {
embedder_fields_[i] = embedder_fields[i];
}
}
void Invoke(Isolate* isolate);
void Invoke(Isolate* isolate, InvocationType type);
Node* node() const { return node_; }
Data::Callback callback() const { return callback_; }
private:
Node* node_;
Data::Callback callback_;
void* parameter_;
void* embedder_fields_[v8::kEmbedderFieldsInWeakCallback];
......
......@@ -488,6 +488,63 @@ TEST(TracedGlobalIteration) {
CHECK_EQ(1, visitor.count());
}
namespace {
void FinalizationCallback(const WeakCallbackInfo<void>& data) {
v8::TracedGlobal<v8::Object>* traced =
reinterpret_cast<v8::TracedGlobal<v8::Object>*>(data.GetParameter());
CHECK_EQ(reinterpret_cast<void*>(0x4), data.GetInternalField(0));
CHECK_EQ(reinterpret_cast<void*>(0x8), data.GetInternalField(1));
traced->Reset();
}
} // namespace
TEST(TracedGlobalSetFinalizationCallbackScavenge) {
ManualGCScope manual_gc;
CcTest::InitializeVM();
v8::Isolate* isolate = CcTest::isolate();
v8::HandleScope scope(isolate);
TestEmbedderHeapTracer tracer;
tracer.ConsiderTracedGlobalAsRoot(false);
TemporaryEmbedderHeapTracerScope tracer_scope(isolate, &tracer);
v8::TracedGlobal<v8::Object> traced;
ConstructJSApiObject(isolate, isolate->GetCurrentContext(), &traced);
CHECK(!traced.IsEmpty());
{
v8::HandleScope scope(isolate);
auto local = traced.Get(isolate);
local->SetAlignedPointerInInternalField(0, reinterpret_cast<void*>(0x4));
local->SetAlignedPointerInInternalField(1, reinterpret_cast<void*>(0x8));
}
traced.SetFinalizationCallback(&traced, FinalizationCallback);
heap::InvokeScavenge();
CHECK(traced.IsEmpty());
}
TEST(TracedGlobalSetFinalizationCallbackMarkSweep) {
ManualGCScope manual_gc;
CcTest::InitializeVM();
v8::Isolate* isolate = CcTest::isolate();
v8::HandleScope scope(isolate);
TestEmbedderHeapTracer tracer;
TemporaryEmbedderHeapTracerScope tracer_scope(isolate, &tracer);
v8::TracedGlobal<v8::Object> traced;
ConstructJSApiObject(isolate, isolate->GetCurrentContext(), &traced);
CHECK(!traced.IsEmpty());
{
v8::HandleScope scope(isolate);
auto local = traced.Get(isolate);
local->SetAlignedPointerInInternalField(0, reinterpret_cast<void*>(0x4));
local->SetAlignedPointerInInternalField(1, reinterpret_cast<void*>(0x8));
}
traced.SetFinalizationCallback(&traced, FinalizationCallback);
heap::InvokeMarkSweep();
CHECK(traced.IsEmpty());
}
} // namespace heap
} // namespace internal
} // namespace v8
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment