[api] Add optional data pointer to GC callbacks
This can be useful when there may be multiple callbacks attached by code that's not directly tied to a single isolate, e.g. working on a per-context basis. This also allows rephrasing the global non-isolate APIs in terms of this new API, rather than working around it inside `src/heap`. TBR=hpayer@chromium.org Bug: Cq-Include-Trybots: master.tryserver.chromium.linux:linux_chromium_rel_ng Change-Id: I2e490ec40d1a34ea812f25f41ef9741d2116d965 Reviewed-on: https://chromium-review.googlesource.com/647548 Reviewed-by: Yang Guo <yangguo@chromium.org> Reviewed-by: Adam Klein <adamk@chromium.org> Commit-Queue: Yang Guo <yangguo@chromium.org> Cr-Commit-Position: refs/heads/master@{#47923}
This commit is contained in:
parent
6e8c00f7df
commit
9b21865822
@ -7309,6 +7309,8 @@ class V8_EXPORT Isolate {
|
||||
|
||||
typedef void (*GCCallback)(Isolate* isolate, GCType type,
|
||||
GCCallbackFlags flags);
|
||||
typedef void (*GCCallbackWithData)(Isolate* isolate, GCType type,
|
||||
GCCallbackFlags flags, void* data);
|
||||
|
||||
/**
|
||||
* Enables the host application to receive a notification before a
|
||||
@ -7319,6 +7321,8 @@ class V8_EXPORT Isolate {
|
||||
* not possible to register the same callback function two times with
|
||||
* different GCType filters.
|
||||
*/
|
||||
void AddGCPrologueCallback(GCCallbackWithData callback, void* data = nullptr,
|
||||
GCType gc_type_filter = kGCTypeAll);
|
||||
void AddGCPrologueCallback(GCCallback callback,
|
||||
GCType gc_type_filter = kGCTypeAll);
|
||||
|
||||
@ -7326,6 +7330,7 @@ class V8_EXPORT Isolate {
|
||||
* This function removes callback which was installed by
|
||||
* AddGCPrologueCallback function.
|
||||
*/
|
||||
void RemoveGCPrologueCallback(GCCallbackWithData, void* data = nullptr);
|
||||
void RemoveGCPrologueCallback(GCCallback callback);
|
||||
|
||||
/**
|
||||
@ -7342,6 +7347,8 @@ class V8_EXPORT Isolate {
|
||||
* not possible to register the same callback function two times with
|
||||
* different GCType filters.
|
||||
*/
|
||||
void AddGCEpilogueCallback(GCCallbackWithData callback, void* data = nullptr,
|
||||
GCType gc_type_filter = kGCTypeAll);
|
||||
void AddGCEpilogueCallback(GCCallback callback,
|
||||
GCType gc_type_filter = kGCTypeAll);
|
||||
|
||||
@ -7349,6 +7356,8 @@ class V8_EXPORT Isolate {
|
||||
* This function removes callback which was installed by
|
||||
* AddGCEpilogueCallback function.
|
||||
*/
|
||||
void RemoveGCEpilogueCallback(GCCallbackWithData callback,
|
||||
void* data = nullptr);
|
||||
void RemoveGCEpilogueCallback(GCCallback callback);
|
||||
|
||||
typedef size_t (*GetExternallyAllocatedMemoryInBytesCallback)();
|
||||
|
67
src/api.cc
67
src/api.cc
@ -8483,41 +8483,70 @@ v8::Local<Value> Isolate::ThrowException(v8::Local<v8::Value> value) {
|
||||
return v8::Undefined(reinterpret_cast<v8::Isolate*>(isolate));
|
||||
}
|
||||
|
||||
void Isolate::AddGCPrologueCallback(GCCallback callback, GCType gc_type) {
|
||||
void Isolate::AddGCPrologueCallback(GCCallbackWithData callback, void* data,
|
||||
GCType gc_type) {
|
||||
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);
|
||||
isolate->heap()->AddGCPrologueCallback(callback, gc_type);
|
||||
isolate->heap()->AddGCPrologueCallback(callback, gc_type, data);
|
||||
}
|
||||
|
||||
void Isolate::RemoveGCPrologueCallback(GCCallbackWithData callback,
|
||||
void* data) {
|
||||
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);
|
||||
isolate->heap()->RemoveGCPrologueCallback(callback, data);
|
||||
}
|
||||
|
||||
void Isolate::AddGCEpilogueCallback(GCCallbackWithData callback, void* data,
|
||||
GCType gc_type) {
|
||||
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);
|
||||
isolate->heap()->AddGCEpilogueCallback(callback, gc_type, data);
|
||||
}
|
||||
|
||||
void Isolate::RemoveGCEpilogueCallback(GCCallbackWithData callback,
|
||||
void* data) {
|
||||
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);
|
||||
isolate->heap()->RemoveGCEpilogueCallback(callback, data);
|
||||
}
|
||||
|
||||
static void CallGCCallbackWithoutData(Isolate* isolate, GCType type,
|
||||
GCCallbackFlags flags, void* data) {
|
||||
reinterpret_cast<Isolate::GCCallback>(data)(isolate, type, flags);
|
||||
}
|
||||
|
||||
void Isolate::AddGCPrologueCallback(GCCallback callback, GCType gc_type) {
|
||||
void* data = reinterpret_cast<void*>(callback);
|
||||
AddGCPrologueCallback(CallGCCallbackWithoutData, data, gc_type);
|
||||
}
|
||||
|
||||
void Isolate::RemoveGCPrologueCallback(GCCallback callback) {
|
||||
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);
|
||||
isolate->heap()->RemoveGCPrologueCallback(callback);
|
||||
void* data = reinterpret_cast<void*>(callback);
|
||||
RemoveGCPrologueCallback(CallGCCallbackWithoutData, data);
|
||||
}
|
||||
|
||||
|
||||
void Isolate::AddGCEpilogueCallback(GCCallback callback, GCType gc_type) {
|
||||
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);
|
||||
isolate->heap()->AddGCEpilogueCallback(callback, gc_type);
|
||||
void* data = reinterpret_cast<void*>(callback);
|
||||
AddGCEpilogueCallback(CallGCCallbackWithoutData, data, gc_type);
|
||||
}
|
||||
|
||||
|
||||
void Isolate::RemoveGCEpilogueCallback(GCCallback callback) {
|
||||
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);
|
||||
isolate->heap()->RemoveGCEpilogueCallback(callback);
|
||||
void* data = reinterpret_cast<void*>(callback);
|
||||
RemoveGCEpilogueCallback(CallGCCallbackWithoutData, data);
|
||||
}
|
||||
|
||||
|
||||
void V8::AddGCPrologueCallback(GCCallback callback, GCType gc_type) {
|
||||
i::Isolate* isolate = i::Isolate::Current();
|
||||
isolate->heap()->AddGCPrologueCallback(
|
||||
reinterpret_cast<v8::Isolate::GCCallback>(callback), gc_type, false);
|
||||
static void CallGCCallbackWithoutIsolate(Isolate* isolate, GCType type,
|
||||
GCCallbackFlags flags, void* data) {
|
||||
reinterpret_cast<v8::GCCallback>(data)(type, flags);
|
||||
}
|
||||
|
||||
void V8::AddGCPrologueCallback(v8::GCCallback callback, GCType gc_type) {
|
||||
void* data = reinterpret_cast<void*>(callback);
|
||||
Isolate::GetCurrent()->AddGCPrologueCallback(CallGCCallbackWithoutIsolate,
|
||||
data, gc_type);
|
||||
}
|
||||
|
||||
void V8::AddGCEpilogueCallback(GCCallback callback, GCType gc_type) {
|
||||
i::Isolate* isolate = i::Isolate::Current();
|
||||
isolate->heap()->AddGCEpilogueCallback(
|
||||
reinterpret_cast<v8::Isolate::GCCallback>(callback), gc_type, false);
|
||||
void V8::AddGCEpilogueCallback(v8::GCCallback callback, GCType gc_type) {
|
||||
void* data = reinterpret_cast<void*>(callback);
|
||||
Isolate::GetCurrent()->AddGCEpilogueCallback(CallGCCallbackWithoutIsolate,
|
||||
data, gc_type);
|
||||
}
|
||||
|
||||
void Isolate::SetEmbedderHeapTracer(EmbedderHeapTracer* tracer) {
|
||||
|
@ -107,15 +107,16 @@ void Heap::SetSerializedGlobalProxySizes(FixedArray* sizes) {
|
||||
set_serialized_global_proxy_sizes(sizes);
|
||||
}
|
||||
|
||||
bool Heap::GCCallbackPair::operator==(const Heap::GCCallbackPair& other) const {
|
||||
return other.callback == callback;
|
||||
bool Heap::GCCallbackTuple::operator==(
|
||||
const Heap::GCCallbackTuple& other) const {
|
||||
return other.callback == callback && other.data == data;
|
||||
}
|
||||
|
||||
Heap::GCCallbackPair& Heap::GCCallbackPair::operator=(
|
||||
const Heap::GCCallbackPair& other) {
|
||||
Heap::GCCallbackTuple& Heap::GCCallbackTuple::operator=(
|
||||
const Heap::GCCallbackTuple& other) {
|
||||
callback = other.callback;
|
||||
gc_type = other.gc_type;
|
||||
pass_isolate = other.pass_isolate;
|
||||
data = other.data;
|
||||
return *this;
|
||||
}
|
||||
|
||||
@ -1654,35 +1655,21 @@ bool Heap::PerformGarbageCollection(
|
||||
void Heap::CallGCPrologueCallbacks(GCType gc_type, GCCallbackFlags flags) {
|
||||
RuntimeCallTimerScope runtime_timer(isolate(),
|
||||
&RuntimeCallStats::GCPrologueCallback);
|
||||
for (const GCCallbackPair& info : gc_prologue_callbacks_) {
|
||||
for (const GCCallbackTuple& info : gc_prologue_callbacks_) {
|
||||
if (gc_type & info.gc_type) {
|
||||
if (!info.pass_isolate) {
|
||||
v8::GCCallback callback =
|
||||
reinterpret_cast<v8::GCCallback>(info.callback);
|
||||
callback(gc_type, flags);
|
||||
} else {
|
||||
v8::Isolate* isolate = reinterpret_cast<v8::Isolate*>(this->isolate());
|
||||
info.callback(isolate, gc_type, flags);
|
||||
}
|
||||
v8::Isolate* isolate = reinterpret_cast<v8::Isolate*>(this->isolate());
|
||||
info.callback(isolate, gc_type, flags, info.data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void Heap::CallGCEpilogueCallbacks(GCType gc_type,
|
||||
GCCallbackFlags gc_callback_flags) {
|
||||
void Heap::CallGCEpilogueCallbacks(GCType gc_type, GCCallbackFlags flags) {
|
||||
RuntimeCallTimerScope runtime_timer(isolate(),
|
||||
&RuntimeCallStats::GCEpilogueCallback);
|
||||
for (const GCCallbackPair& info : gc_epilogue_callbacks_) {
|
||||
for (const GCCallbackTuple& info : gc_epilogue_callbacks_) {
|
||||
if (gc_type & info.gc_type) {
|
||||
if (!info.pass_isolate) {
|
||||
v8::GCCallback callback =
|
||||
reinterpret_cast<v8::GCCallback>(info.callback);
|
||||
callback(gc_type, gc_callback_flags);
|
||||
} else {
|
||||
v8::Isolate* isolate = reinterpret_cast<v8::Isolate*>(this->isolate());
|
||||
info.callback(isolate, gc_type, gc_callback_flags);
|
||||
}
|
||||
v8::Isolate* isolate = reinterpret_cast<v8::Isolate*>(this->isolate());
|
||||
info.callback(isolate, gc_type, flags, info.data);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -5669,21 +5656,21 @@ void Heap::TearDown() {
|
||||
memory_allocator_ = nullptr;
|
||||
}
|
||||
|
||||
|
||||
void Heap::AddGCPrologueCallback(v8::Isolate::GCCallback callback,
|
||||
GCType gc_type, bool pass_isolate) {
|
||||
void Heap::AddGCPrologueCallback(v8::Isolate::GCCallbackWithData callback,
|
||||
GCType gc_type, void* data) {
|
||||
DCHECK_NOT_NULL(callback);
|
||||
DCHECK(gc_prologue_callbacks_.end() ==
|
||||
std::find(gc_prologue_callbacks_.begin(), gc_prologue_callbacks_.end(),
|
||||
GCCallbackPair(callback, gc_type, pass_isolate)));
|
||||
gc_prologue_callbacks_.emplace_back(callback, gc_type, pass_isolate);
|
||||
GCCallbackTuple(callback, gc_type, data)));
|
||||
gc_prologue_callbacks_.emplace_back(callback, gc_type, data);
|
||||
}
|
||||
|
||||
|
||||
void Heap::RemoveGCPrologueCallback(v8::Isolate::GCCallback callback) {
|
||||
void Heap::RemoveGCPrologueCallback(v8::Isolate::GCCallbackWithData callback,
|
||||
void* data) {
|
||||
DCHECK_NOT_NULL(callback);
|
||||
for (size_t i = 0; i < gc_prologue_callbacks_.size(); i++) {
|
||||
if (gc_prologue_callbacks_[i].callback == callback) {
|
||||
if (gc_prologue_callbacks_[i].callback == callback &&
|
||||
gc_prologue_callbacks_[i].data == data) {
|
||||
gc_prologue_callbacks_[i] = gc_prologue_callbacks_.back();
|
||||
gc_prologue_callbacks_.pop_back();
|
||||
return;
|
||||
@ -5692,21 +5679,21 @@ void Heap::RemoveGCPrologueCallback(v8::Isolate::GCCallback callback) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
|
||||
void Heap::AddGCEpilogueCallback(v8::Isolate::GCCallback callback,
|
||||
GCType gc_type, bool pass_isolate) {
|
||||
void Heap::AddGCEpilogueCallback(v8::Isolate::GCCallbackWithData callback,
|
||||
GCType gc_type, void* data) {
|
||||
DCHECK_NOT_NULL(callback);
|
||||
DCHECK(gc_epilogue_callbacks_.end() ==
|
||||
std::find(gc_epilogue_callbacks_.begin(), gc_epilogue_callbacks_.end(),
|
||||
GCCallbackPair(callback, gc_type, pass_isolate)));
|
||||
gc_epilogue_callbacks_.emplace_back(callback, gc_type, pass_isolate);
|
||||
GCCallbackTuple(callback, gc_type, data)));
|
||||
gc_epilogue_callbacks_.emplace_back(callback, gc_type, data);
|
||||
}
|
||||
|
||||
|
||||
void Heap::RemoveGCEpilogueCallback(v8::Isolate::GCCallback callback) {
|
||||
void Heap::RemoveGCEpilogueCallback(v8::Isolate::GCCallbackWithData callback,
|
||||
void* data) {
|
||||
DCHECK_NOT_NULL(callback);
|
||||
for (size_t i = 0; i < gc_epilogue_callbacks_.size(); i++) {
|
||||
if (gc_epilogue_callbacks_[i].callback == callback) {
|
||||
if (gc_epilogue_callbacks_[i].callback == callback &&
|
||||
gc_epilogue_callbacks_[i].data == data) {
|
||||
gc_epilogue_callbacks_[i] = gc_epilogue_callbacks_.back();
|
||||
gc_epilogue_callbacks_.pop_back();
|
||||
return;
|
||||
|
@ -1433,13 +1433,15 @@ class Heap {
|
||||
// Prologue/epilogue callback methods.========================================
|
||||
// ===========================================================================
|
||||
|
||||
void AddGCPrologueCallback(v8::Isolate::GCCallback callback,
|
||||
GCType gc_type_filter, bool pass_isolate = true);
|
||||
void RemoveGCPrologueCallback(v8::Isolate::GCCallback callback);
|
||||
void AddGCPrologueCallback(v8::Isolate::GCCallbackWithData callback,
|
||||
GCType gc_type_filter, void* data);
|
||||
void RemoveGCPrologueCallback(v8::Isolate::GCCallbackWithData callback,
|
||||
void* data);
|
||||
|
||||
void AddGCEpilogueCallback(v8::Isolate::GCCallback callback,
|
||||
GCType gc_type_filter, bool pass_isolate = true);
|
||||
void RemoveGCEpilogueCallback(v8::Isolate::GCCallback callback);
|
||||
void AddGCEpilogueCallback(v8::Isolate::GCCallbackWithData callback,
|
||||
GCType gc_type_filter, void* data);
|
||||
void RemoveGCEpilogueCallback(v8::Isolate::GCCallbackWithData callback,
|
||||
void* data);
|
||||
|
||||
void CallGCPrologueCallbacks(GCType gc_type, GCCallbackFlags flags);
|
||||
void CallGCEpilogueCallbacks(GCType gc_type, GCCallbackFlags flags);
|
||||
@ -1605,17 +1607,17 @@ class Heap {
|
||||
RootListIndex index;
|
||||
};
|
||||
|
||||
struct GCCallbackPair {
|
||||
GCCallbackPair(v8::Isolate::GCCallback callback, GCType gc_type,
|
||||
bool pass_isolate)
|
||||
: callback(callback), gc_type(gc_type), pass_isolate(pass_isolate) {}
|
||||
struct GCCallbackTuple {
|
||||
GCCallbackTuple(v8::Isolate::GCCallbackWithData callback, GCType gc_type,
|
||||
void* data)
|
||||
: callback(callback), gc_type(gc_type), data(data) {}
|
||||
|
||||
bool operator==(const GCCallbackPair& other) const;
|
||||
GCCallbackPair& operator=(const GCCallbackPair& other);
|
||||
bool operator==(const GCCallbackTuple& other) const;
|
||||
GCCallbackTuple& operator=(const GCCallbackTuple& other);
|
||||
|
||||
v8::Isolate::GCCallback callback;
|
||||
v8::Isolate::GCCallbackWithData callback;
|
||||
GCType gc_type;
|
||||
bool pass_isolate;
|
||||
void* data;
|
||||
};
|
||||
|
||||
static const int kInitialStringTableSize = 2048;
|
||||
@ -2300,8 +2302,8 @@ class Heap {
|
||||
// contains Smi(0) while marking is not active.
|
||||
Object* encountered_weak_collections_;
|
||||
|
||||
std::vector<GCCallbackPair> gc_epilogue_callbacks_;
|
||||
std::vector<GCCallbackPair> gc_prologue_callbacks_;
|
||||
std::vector<GCCallbackTuple> gc_epilogue_callbacks_;
|
||||
std::vector<GCCallbackTuple> gc_prologue_callbacks_;
|
||||
|
||||
GetExternallyAllocatedMemoryInBytesCallback external_memory_callback_;
|
||||
|
||||
|
@ -19693,6 +19693,19 @@ void EpilogueCallbackSecond(v8::Isolate* isolate,
|
||||
++epilogue_call_count_second;
|
||||
}
|
||||
|
||||
void PrologueCallbackNew(v8::Isolate* isolate, v8::GCType,
|
||||
v8::GCCallbackFlags flags, void* data) {
|
||||
CHECK_EQ(flags, v8::kNoGCCallbackFlags);
|
||||
CHECK_EQ(gc_callbacks_isolate, isolate);
|
||||
++*static_cast<int*>(data);
|
||||
}
|
||||
|
||||
void EpilogueCallbackNew(v8::Isolate* isolate, v8::GCType,
|
||||
v8::GCCallbackFlags flags, void* data) {
|
||||
CHECK_EQ(flags, v8::kNoGCCallbackFlags);
|
||||
CHECK_EQ(gc_callbacks_isolate, isolate);
|
||||
++*static_cast<int*>(data);
|
||||
}
|
||||
|
||||
void PrologueCallbackAlloc(v8::Isolate* isolate,
|
||||
v8::GCType,
|
||||
@ -19767,6 +19780,52 @@ TEST(GCCallbacksOld) {
|
||||
CHECK_EQ(2, epilogue_call_count_second);
|
||||
}
|
||||
|
||||
TEST(GCCallbacksWithData) {
|
||||
LocalContext context;
|
||||
|
||||
gc_callbacks_isolate = context->GetIsolate();
|
||||
int prologue1 = 0;
|
||||
int epilogue1 = 0;
|
||||
int prologue2 = 0;
|
||||
int epilogue2 = 0;
|
||||
|
||||
context->GetIsolate()->AddGCPrologueCallback(PrologueCallbackNew, &prologue1);
|
||||
context->GetIsolate()->AddGCEpilogueCallback(EpilogueCallbackNew, &epilogue1);
|
||||
CHECK_EQ(0, prologue1);
|
||||
CHECK_EQ(0, epilogue1);
|
||||
CHECK_EQ(0, prologue2);
|
||||
CHECK_EQ(0, epilogue2);
|
||||
CcTest::CollectAllGarbage();
|
||||
CHECK_EQ(1, prologue1);
|
||||
CHECK_EQ(1, epilogue1);
|
||||
CHECK_EQ(0, prologue2);
|
||||
CHECK_EQ(0, epilogue2);
|
||||
context->GetIsolate()->AddGCPrologueCallback(PrologueCallbackNew, &prologue2);
|
||||
context->GetIsolate()->AddGCEpilogueCallback(EpilogueCallbackNew, &epilogue2);
|
||||
CcTest::CollectAllGarbage();
|
||||
CHECK_EQ(2, prologue1);
|
||||
CHECK_EQ(2, epilogue1);
|
||||
CHECK_EQ(1, prologue2);
|
||||
CHECK_EQ(1, epilogue2);
|
||||
context->GetIsolate()->RemoveGCPrologueCallback(PrologueCallbackNew,
|
||||
&prologue1);
|
||||
context->GetIsolate()->RemoveGCEpilogueCallback(EpilogueCallbackNew,
|
||||
&epilogue1);
|
||||
CcTest::CollectAllGarbage();
|
||||
CHECK_EQ(2, prologue1);
|
||||
CHECK_EQ(2, epilogue1);
|
||||
CHECK_EQ(2, prologue2);
|
||||
CHECK_EQ(2, epilogue2);
|
||||
context->GetIsolate()->RemoveGCPrologueCallback(PrologueCallbackNew,
|
||||
&prologue2);
|
||||
context->GetIsolate()->RemoveGCEpilogueCallback(EpilogueCallbackNew,
|
||||
&epilogue2);
|
||||
CcTest::CollectAllGarbage();
|
||||
CHECK_EQ(2, prologue1);
|
||||
CHECK_EQ(2, epilogue1);
|
||||
CHECK_EQ(2, prologue2);
|
||||
CHECK_EQ(2, epilogue2);
|
||||
}
|
||||
|
||||
TEST(GCCallbacks) {
|
||||
LocalContext context;
|
||||
|
Loading…
Reference in New Issue
Block a user