Commit f3434003 authored by dcarney@chromium.org's avatar dcarney@chromium.org

new gc callbacks with isolate parameters

R=svenpanne@chromium.org
BUG=

Review URL: https://codereview.chromium.org/24065005

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@16770 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 873050f1
......@@ -3871,8 +3871,6 @@ enum GCCallbackFlags {
typedef void (*GCPrologueCallback)(GCType type, GCCallbackFlags flags);
typedef void (*GCEpilogueCallback)(GCType type, GCCallbackFlags flags);
typedef void (*GCCallback)();
/**
* Collection of V8 heap information.
......@@ -4056,6 +4054,51 @@ class V8_EXPORT Isolate {
void SetReference(const Persistent<Object>& parent,
const Persistent<Value>& child);
typedef void (*GCPrologueCallback)(Isolate* isolate,
GCType type,
GCCallbackFlags flags);
typedef void (*GCEpilogueCallback)(Isolate* isolate,
GCType type,
GCCallbackFlags flags);
/**
* Enables the host application to receive a notification before a
* garbage collection. Allocations are not allowed in the
* callback function, you therefore cannot manipulate objects (set
* or delete properties for example) since it is possible such
* operations will result in the allocation of objects. It is possible
* to specify the GCType filter for your callback. But it is not possible to
* register the same callback function two times with different
* GCType filters.
*/
void AddGCPrologueCallback(
GCPrologueCallback callback, GCType gc_type_filter = kGCTypeAll);
/**
* This function removes callback which was installed by
* AddGCPrologueCallback function.
*/
void RemoveGCPrologueCallback(GCPrologueCallback callback);
/**
* Enables the host application to receive a notification after a
* garbage collection. Allocations are not allowed in the
* callback function, you therefore cannot manipulate objects (set
* or delete properties for example) since it is possible such
* operations will result in the allocation of objects. It is possible
* to specify the GCType filter for your callback. But it is not possible to
* register the same callback function two times with different
* GCType filters.
*/
void AddGCEpilogueCallback(
GCEpilogueCallback callback, GCType gc_type_filter = kGCTypeAll);
/**
* This function removes callback which was installed by
* AddGCEpilogueCallback function.
*/
void RemoveGCEpilogueCallback(GCEpilogueCallback callback);
private:
Isolate();
Isolate(const Isolate&);
......@@ -4412,16 +4455,6 @@ class V8_EXPORT V8 {
*/
static void RemoveGCPrologueCallback(GCPrologueCallback callback);
/**
* The function is deprecated. Please use AddGCPrologueCallback instead.
* Enables the host application to receive a notification before a
* garbage collection. Allocations are not allowed in the
* callback function, you therefore cannot manipulate objects (set
* or delete properties for example) since it is possible such
* operations will result in the allocation of objects.
*/
V8_DEPRECATED(static void SetGlobalGCPrologueCallback(GCCallback));
/**
* Enables the host application to receive a notification after a
* garbage collection. Allocations are not allowed in the
......@@ -4441,16 +4474,6 @@ class V8_EXPORT V8 {
*/
static void RemoveGCEpilogueCallback(GCEpilogueCallback callback);
/**
* The function is deprecated. Please use AddGCEpilogueCallback instead.
* Enables the host application to receive a notification after a
* major garbage collection. Allocations are not allowed in the
* callback function, you therefore cannot manipulate objects (set
* or delete properties for example) since it is possible such
* operations will result in the allocation of objects.
*/
V8_DEPRECATED(static void SetGlobalGCEpilogueCallback(GCCallback));
/**
* Enables the host application to provide a mechanism to be notified
* and perform custom logging when V8 Allocates Executable Memory.
......
......@@ -6685,45 +6685,65 @@ void Isolate::SetReference(const Persistent<Object>& parent,
}
void V8::SetGlobalGCPrologueCallback(GCCallback callback) {
i::Isolate* isolate = i::Isolate::Current();
if (IsDeadCheck(isolate, "v8::V8::SetGlobalGCPrologueCallback()")) return;
isolate->heap()->SetGlobalGCPrologueCallback(callback);
void Isolate::AddGCPrologueCallback(GCPrologueCallback callback,
GCType gc_type) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);
isolate->heap()->AddGCPrologueCallback(callback, gc_type);
}
void V8::SetGlobalGCEpilogueCallback(GCCallback callback) {
i::Isolate* isolate = i::Isolate::Current();
if (IsDeadCheck(isolate, "v8::V8::SetGlobalGCEpilogueCallback()")) return;
isolate->heap()->SetGlobalGCEpilogueCallback(callback);
void Isolate::RemoveGCPrologueCallback(GCPrologueCallback callback) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);
isolate->heap()->RemoveGCPrologueCallback(callback);
}
void Isolate::AddGCEpilogueCallback(GCEpilogueCallback callback,
GCType gc_type) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);
isolate->heap()->AddGCEpilogueCallback(callback, gc_type);
}
void Isolate::RemoveGCEpilogueCallback(GCEpilogueCallback callback) {
i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);
isolate->heap()->RemoveGCEpilogueCallback(callback);
}
void V8::AddGCPrologueCallback(GCPrologueCallback callback, GCType gc_type) {
i::Isolate* isolate = i::Isolate::Current();
if (IsDeadCheck(isolate, "v8::V8::AddGCPrologueCallback()")) return;
isolate->heap()->AddGCPrologueCallback(callback, gc_type);
isolate->heap()->AddGCPrologueCallback(
reinterpret_cast<v8::Isolate::GCPrologueCallback>(callback),
gc_type,
false);
}
void V8::RemoveGCPrologueCallback(GCPrologueCallback callback) {
i::Isolate* isolate = i::Isolate::Current();
if (IsDeadCheck(isolate, "v8::V8::RemoveGCPrologueCallback()")) return;
isolate->heap()->RemoveGCPrologueCallback(callback);
isolate->heap()->RemoveGCPrologueCallback(
reinterpret_cast<v8::Isolate::GCPrologueCallback>(callback));
}
void V8::AddGCEpilogueCallback(GCEpilogueCallback callback, GCType gc_type) {
i::Isolate* isolate = i::Isolate::Current();
if (IsDeadCheck(isolate, "v8::V8::AddGCEpilogueCallback()")) return;
isolate->heap()->AddGCEpilogueCallback(callback, gc_type);
isolate->heap()->AddGCEpilogueCallback(
reinterpret_cast<v8::Isolate::GCEpilogueCallback>(callback),
gc_type,
false);
}
void V8::RemoveGCEpilogueCallback(GCEpilogueCallback callback) {
i::Isolate* isolate = i::Isolate::Current();
if (IsDeadCheck(isolate, "v8::V8::RemoveGCEpilogueCallback()")) return;
isolate->heap()->RemoveGCEpilogueCallback(callback);
isolate->heap()->RemoveGCEpilogueCallback(
reinterpret_cast<v8::Isolate::GCEpilogueCallback>(callback));
}
......
......@@ -129,8 +129,6 @@ Heap::Heap()
old_gen_exhausted_(false),
store_buffer_rebuilder_(store_buffer()),
hidden_string_(NULL),
global_gc_prologue_callback_(NULL),
global_gc_epilogue_callback_(NULL),
gc_safe_size_of_old_object_(NULL),
total_regexp_code_generated_(0),
tracer_(NULL),
......@@ -1055,12 +1053,17 @@ bool Heap::PerformGarbageCollection(GarbageCollector collector,
void Heap::CallGCPrologueCallbacks(GCType gc_type, GCCallbackFlags flags) {
if (gc_type == kGCTypeMarkSweepCompact && global_gc_prologue_callback_) {
global_gc_prologue_callback_();
}
for (int i = 0; i < gc_prologue_callbacks_.length(); ++i) {
if (gc_type & gc_prologue_callbacks_[i].gc_type) {
gc_prologue_callbacks_[i].callback(gc_type, flags);
if (!gc_prologue_callbacks_[i].pass_isolate_) {
v8::GCPrologueCallback callback =
reinterpret_cast<v8::GCPrologueCallback>(
gc_prologue_callbacks_[i].callback);
callback(gc_type, flags);
} else {
v8::Isolate* isolate = reinterpret_cast<v8::Isolate*>(this->isolate());
gc_prologue_callbacks_[i].callback(isolate, gc_type, flags);
}
}
}
}
......@@ -1069,12 +1072,18 @@ void Heap::CallGCPrologueCallbacks(GCType gc_type, GCCallbackFlags flags) {
void Heap::CallGCEpilogueCallbacks(GCType gc_type) {
for (int i = 0; i < gc_epilogue_callbacks_.length(); ++i) {
if (gc_type & gc_epilogue_callbacks_[i].gc_type) {
gc_epilogue_callbacks_[i].callback(gc_type, kNoGCCallbackFlags);
if (!gc_epilogue_callbacks_[i].pass_isolate_) {
v8::GCPrologueCallback callback =
reinterpret_cast<v8::GCPrologueCallback>(
gc_epilogue_callbacks_[i].callback);
callback(gc_type, kNoGCCallbackFlags);
} else {
v8::Isolate* isolate = reinterpret_cast<v8::Isolate*>(this->isolate());
gc_epilogue_callbacks_[i].callback(
isolate, gc_type, kNoGCCallbackFlags);
}
}
}
if (gc_type == kGCTypeMarkSweepCompact && global_gc_epilogue_callback_) {
global_gc_epilogue_callback_();
}
}
......@@ -7071,15 +7080,17 @@ void Heap::TearDown() {
}
void Heap::AddGCPrologueCallback(GCPrologueCallback callback, GCType gc_type) {
void Heap::AddGCPrologueCallback(v8::Isolate::GCPrologueCallback callback,
GCType gc_type,
bool pass_isolate) {
ASSERT(callback != NULL);
GCPrologueCallbackPair pair(callback, gc_type);
GCPrologueCallbackPair pair(callback, gc_type, pass_isolate);
ASSERT(!gc_prologue_callbacks_.Contains(pair));
return gc_prologue_callbacks_.Add(pair);
}
void Heap::RemoveGCPrologueCallback(GCPrologueCallback callback) {
void Heap::RemoveGCPrologueCallback(v8::Isolate::GCPrologueCallback callback) {
ASSERT(callback != NULL);
for (int i = 0; i < gc_prologue_callbacks_.length(); ++i) {
if (gc_prologue_callbacks_[i].callback == callback) {
......@@ -7091,15 +7102,17 @@ void Heap::RemoveGCPrologueCallback(GCPrologueCallback callback) {
}
void Heap::AddGCEpilogueCallback(GCEpilogueCallback callback, GCType gc_type) {
void Heap::AddGCEpilogueCallback(v8::Isolate::GCEpilogueCallback callback,
GCType gc_type,
bool pass_isolate) {
ASSERT(callback != NULL);
GCEpilogueCallbackPair pair(callback, gc_type);
GCEpilogueCallbackPair pair(callback, gc_type, pass_isolate);
ASSERT(!gc_epilogue_callbacks_.Contains(pair));
return gc_epilogue_callbacks_.Add(pair);
}
void Heap::RemoveGCEpilogueCallback(GCEpilogueCallback callback) {
void Heap::RemoveGCEpilogueCallback(v8::Isolate::GCEpilogueCallback callback) {
ASSERT(callback != NULL);
for (int i = 0; i < gc_epilogue_callbacks_.length(); ++i) {
if (gc_epilogue_callbacks_[i].callback == callback) {
......
......@@ -1272,22 +1272,15 @@ class Heap {
void GarbageCollectionGreedyCheck();
#endif
void AddGCPrologueCallback(
GCPrologueCallback callback, GCType gc_type_filter);
void RemoveGCPrologueCallback(GCPrologueCallback callback);
void AddGCPrologueCallback(v8::Isolate::GCPrologueCallback callback,
GCType gc_type_filter,
bool pass_isolate = true);
void RemoveGCPrologueCallback(v8::Isolate::GCPrologueCallback callback);
void AddGCEpilogueCallback(
GCEpilogueCallback callback, GCType gc_type_filter);
void RemoveGCEpilogueCallback(GCEpilogueCallback callback);
void SetGlobalGCPrologueCallback(GCCallback callback) {
ASSERT((callback == NULL) ^ (global_gc_prologue_callback_ == NULL));
global_gc_prologue_callback_ = callback;
}
void SetGlobalGCEpilogueCallback(GCCallback callback) {
ASSERT((callback == NULL) ^ (global_gc_epilogue_callback_ == NULL));
global_gc_epilogue_callback_ = callback;
}
void AddGCEpilogueCallback(v8::Isolate::GCEpilogueCallback callback,
GCType gc_type_filter,
bool pass_isolate = true);
void RemoveGCEpilogueCallback(v8::Isolate::GCEpilogueCallback callback);
// Heap root getters. We have versions with and without type::cast() here.
// You can't use type::cast during GC because the assert fails.
......@@ -2032,32 +2025,37 @@ class Heap {
// GC callback function, called before and after mark-compact GC.
// Allocations in the callback function are disallowed.
struct GCPrologueCallbackPair {
GCPrologueCallbackPair(GCPrologueCallback callback, GCType gc_type)
: callback(callback), gc_type(gc_type) {
GCPrologueCallbackPair(v8::Isolate::GCPrologueCallback callback,
GCType gc_type,
bool pass_isolate)
: callback(callback), gc_type(gc_type), pass_isolate_(pass_isolate) {
}
bool operator==(const GCPrologueCallbackPair& pair) const {
return pair.callback == callback;
}
GCPrologueCallback callback;
v8::Isolate::GCPrologueCallback callback;
GCType gc_type;
// TODO(dcarney): remove variable
bool pass_isolate_;
};
List<GCPrologueCallbackPair> gc_prologue_callbacks_;
struct GCEpilogueCallbackPair {
GCEpilogueCallbackPair(GCEpilogueCallback callback, GCType gc_type)
: callback(callback), gc_type(gc_type) {
GCEpilogueCallbackPair(v8::Isolate::GCPrologueCallback callback,
GCType gc_type,
bool pass_isolate)
: callback(callback), gc_type(gc_type), pass_isolate_(pass_isolate) {
}
bool operator==(const GCEpilogueCallbackPair& pair) const {
return pair.callback == callback;
}
GCEpilogueCallback callback;
v8::Isolate::GCPrologueCallback callback;
GCType gc_type;
// TODO(dcarney): remove variable
bool pass_isolate_;
};
List<GCEpilogueCallbackPair> gc_epilogue_callbacks_;
GCCallback global_gc_prologue_callback_;
GCCallback global_gc_epilogue_callback_;
// Support for computing object sizes during GC.
HeapObjectCallback gc_safe_size_of_old_object_;
static int GcSafeSizeOfOldObject(HeapObject* object);
......
......@@ -17705,32 +17705,73 @@ TEST(Regress618) {
}
}
v8::Isolate* gc_callbacks_isolate = NULL;
int prologue_call_count = 0;
int epilogue_call_count = 0;
int prologue_call_count_second = 0;
int epilogue_call_count_second = 0;
void PrologueCallback(v8::GCType, v8::GCCallbackFlags) {
void PrologueCallback(v8::GCType, v8::GCCallbackFlags flags) {
CHECK_EQ(flags, v8::kNoGCCallbackFlags);
++prologue_call_count;
}
void EpilogueCallback(v8::GCType, v8::GCCallbackFlags) {
void PrologueCallback(v8::Isolate* isolate,
v8::GCType,
v8::GCCallbackFlags flags) {
CHECK_EQ(flags, v8::kNoGCCallbackFlags);
CHECK_EQ(gc_callbacks_isolate, isolate);
++prologue_call_count;
}
void EpilogueCallback(v8::GCType, v8::GCCallbackFlags flags) {
CHECK_EQ(flags, v8::kNoGCCallbackFlags);
++epilogue_call_count;
}
void PrologueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
void EpilogueCallback(v8::Isolate* isolate,
v8::GCType,
v8::GCCallbackFlags flags) {
CHECK_EQ(flags, v8::kNoGCCallbackFlags);
CHECK_EQ(gc_callbacks_isolate, isolate);
++epilogue_call_count;
}
void PrologueCallbackSecond(v8::GCType, v8::GCCallbackFlags flags) {
CHECK_EQ(flags, v8::kNoGCCallbackFlags);
++prologue_call_count_second;
}
void PrologueCallbackSecond(v8::Isolate* isolate,
v8::GCType,
v8::GCCallbackFlags flags) {
CHECK_EQ(flags, v8::kNoGCCallbackFlags);
CHECK_EQ(gc_callbacks_isolate, isolate);
++prologue_call_count_second;
}
void EpilogueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
void EpilogueCallbackSecond(v8::GCType, v8::GCCallbackFlags flags) {
CHECK_EQ(flags, v8::kNoGCCallbackFlags);
++epilogue_call_count_second;
}
TEST(GCCallbacks) {
void EpilogueCallbackSecond(v8::Isolate* isolate,
v8::GCType,
v8::GCCallbackFlags flags) {
CHECK_EQ(flags, v8::kNoGCCallbackFlags);
CHECK_EQ(gc_callbacks_isolate, isolate);
++epilogue_call_count_second;
}
TEST(GCCallbacksOld) {
LocalContext context;
v8::V8::AddGCPrologueCallback(PrologueCallback);
......@@ -17764,6 +17805,41 @@ TEST(GCCallbacks) {
}
TEST(GCCallbacks) {
LocalContext context;
v8::Isolate* isolate = context->GetIsolate();
gc_callbacks_isolate = isolate;
isolate->AddGCPrologueCallback(PrologueCallback);
isolate->AddGCEpilogueCallback(EpilogueCallback);
CHECK_EQ(0, prologue_call_count);
CHECK_EQ(0, epilogue_call_count);
HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
CHECK_EQ(1, prologue_call_count);
CHECK_EQ(1, epilogue_call_count);
isolate->AddGCPrologueCallback(PrologueCallbackSecond);
isolate->AddGCEpilogueCallback(EpilogueCallbackSecond);
HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
CHECK_EQ(2, prologue_call_count);
CHECK_EQ(2, epilogue_call_count);
CHECK_EQ(1, prologue_call_count_second);
CHECK_EQ(1, epilogue_call_count_second);
isolate->RemoveGCPrologueCallback(PrologueCallback);
isolate->RemoveGCEpilogueCallback(EpilogueCallback);
HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
CHECK_EQ(2, prologue_call_count);
CHECK_EQ(2, epilogue_call_count);
CHECK_EQ(2, prologue_call_count_second);
CHECK_EQ(2, epilogue_call_count_second);
isolate->RemoveGCPrologueCallback(PrologueCallbackSecond);
isolate->RemoveGCEpilogueCallback(EpilogueCallbackSecond);
HEAP->CollectAllGarbage(i::Heap::kNoGCFlags);
CHECK_EQ(2, prologue_call_count);
CHECK_EQ(2, epilogue_call_count);
CHECK_EQ(2, prologue_call_count_second);
CHECK_EQ(2, epilogue_call_count_second);
}
THREADED_TEST(AddToJSFunctionResultCache) {
i::FLAG_stress_compaction = false;
i::FLAG_allow_natives_syntax = true;
......
......@@ -267,39 +267,6 @@ TEST(MapCompact) {
}
#endif
static int gc_starts = 0;
static int gc_ends = 0;
static void GCPrologueCallbackFunc() {
CHECK(gc_starts == gc_ends);
gc_starts++;
}
static void GCEpilogueCallbackFunc() {
CHECK(gc_starts == gc_ends + 1);
gc_ends++;
}
TEST(GCCallback) {
i::FLAG_stress_compaction = false;
CcTest::InitializeVM();
HEAP->SetGlobalGCPrologueCallback(&GCPrologueCallbackFunc);
HEAP->SetGlobalGCEpilogueCallback(&GCEpilogueCallbackFunc);
// Scavenge does not call GC callback functions.
HEAP->PerformScavenge();
CHECK_EQ(0, gc_starts);
CHECK_EQ(gc_ends, gc_starts);
HEAP->CollectGarbage(OLD_POINTER_SPACE);
CHECK_EQ(1, gc_starts);
CHECK_EQ(gc_ends, gc_starts);
}
static int NumberOfWeakCalls = 0;
static void WeakPointerCallback(v8::Isolate* isolate,
......
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