New GCCallbacks with additional parameters.

Author: Ilya Tikhonovsky <loislo@chromium.org>
Original issue: http://codereview.chromium.org/1094002

TBR=sgjesse@chromium.org

Review URL: http://codereview.chromium.org/1165004

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@4226 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
mikhail.naganov@gmail.com 2010-03-23 13:11:44 +00:00
parent b278895d28
commit 4d1f8cbfd6
5 changed files with 233 additions and 4 deletions

View File

@ -2158,12 +2158,26 @@ typedef void (*FailedAccessCheckCallback)(Local<Object> target,
// --- G a r b a g e C o l l e c t i o n C a l l b a c k s
/**
* Applications can register a callback function which is called
* before and after a major garbage collection. Allocations are not
* allowed in the callback function, you therefore cannot manipulate
* Applications can register callback functions which will be called
* before and after a garbage collection. Allocations are not
* allowed in the callback functions, you therefore cannot manipulate
* objects (set or delete properties for example) since it is possible
* such operations will result in the allocation of objects.
*/
enum GCType {
kGCTypeScavenge = 1 << 0,
kGCTypeMarkSweepCompact = 1 << 1,
kGCTypeAll = kGCTypeScavenge | kGCTypeMarkSweepCompact
};
enum GCCallbackFlags {
kNoGCCallbackFlags = 0,
kGCCallbackFlagCompacted = 1 << 0
};
typedef void (*GCPrologueCallback)(GCType type, GCCallbackFlags flags);
typedef void (*GCEpilogueCallback)(GCType type, GCCallbackFlags flags);
typedef void (*GCCallback)();
@ -2299,7 +2313,27 @@ class V8EXPORT V8 {
/**
* Enables the host application to receive a notification before a
* major garbage colletion. Allocations are not allowed in the
* 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.
*/
static void AddGCPrologueCallback(
GCPrologueCallback callback, GCType gc_type_filter = kGCTypeAll);
/**
* This function removes callback which was installed by
* AddGCPrologueCallback function.
*/
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.
@ -2307,6 +2341,26 @@ class V8EXPORT V8 {
static void SetGlobalGCPrologueCallback(GCCallback);
/**
* 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.
*/
static void AddGCEpilogueCallback(
GCEpilogueCallback callback, GCType gc_type_filter = kGCTypeAll);
/**
* This function removes callback which was installed by
* AddGCEpilogueCallback function.
*/
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

View File

@ -3546,6 +3546,30 @@ void V8::SetGlobalGCEpilogueCallback(GCCallback callback) {
}
void V8::AddGCPrologueCallback(GCPrologueCallback callback, GCType gc_type) {
if (IsDeadCheck("v8::V8::AddGCPrologueCallback()")) return;
i::Heap::AddGCPrologueCallback(callback, gc_type);
}
void V8::RemoveGCPrologueCallback(GCPrologueCallback callback) {
if (IsDeadCheck("v8::V8::RemoveGCPrologueCallback()")) return;
i::Heap::RemoveGCPrologueCallback(callback);
}
void V8::AddGCEpilogueCallback(GCEpilogueCallback callback, GCType gc_type) {
if (IsDeadCheck("v8::V8::AddGCEpilogueCallback()")) return;
i::Heap::AddGCEpilogueCallback(callback, gc_type);
}
void V8::RemoveGCEpilogueCallback(GCEpilogueCallback callback) {
if (IsDeadCheck("v8::V8::RemoveGCEpilogueCallback()")) return;
i::Heap::RemoveGCEpilogueCallback(callback);
}
void V8::PauseProfiler() {
#ifdef ENABLE_LOGGING_AND_PROFILING
PauseProfilerEx(PROFILER_MODULE_CPU);

View File

@ -98,6 +98,9 @@ size_t Heap::code_range_size_ = 0;
// set up by ConfigureHeap otherwise.
int Heap::reserved_semispace_size_ = Heap::max_semispace_size_;
List<Heap::GCPrologueCallbackPair> Heap::gc_prologue_callbacks_;
List<Heap::GCEpilogueCallbackPair> Heap::gc_epilogue_callbacks_;
GCCallback Heap::global_gc_prologue_callback_ = NULL;
GCCallback Heap::global_gc_epilogue_callback_ = NULL;
@ -547,6 +550,16 @@ void Heap::PerformGarbageCollection(AllocationSpace space,
GCTracer::ExternalScope scope(tracer);
global_gc_prologue_callback_();
}
GCType gc_type =
collector == MARK_COMPACTOR ? kGCTypeMarkSweepCompact : kGCTypeScavenge;
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, kNoGCCallbackFlags);
}
}
EnsureFromSpaceIsCommitted();
// Perform mark-sweep with optional compaction.
@ -585,6 +598,15 @@ void Heap::PerformGarbageCollection(AllocationSpace space,
amount_of_external_allocated_memory_;
}
GCCallbackFlags callback_flags = tracer->is_compacting()
? kGCCallbackFlagCompacted
: kNoGCCallbackFlags;
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, callback_flags);
}
}
if (collector == MARK_COMPACTOR && global_gc_epilogue_callback_) {
ASSERT(!allocation_allowed_);
GCTracer::ExternalScope scope(tracer);
@ -3787,6 +3809,46 @@ void Heap::Unprotect() {
#endif
void Heap::AddGCPrologueCallback(GCPrologueCallback callback, GCType gc_type) {
ASSERT(callback != NULL);
GCPrologueCallbackPair pair(callback, gc_type);
ASSERT(!gc_prologue_callbacks_.Contains(pair));
return gc_prologue_callbacks_.Add(pair);
}
void Heap::RemoveGCPrologueCallback(GCPrologueCallback callback) {
ASSERT(callback != NULL);
for (int i = 0; i < gc_prologue_callbacks_.length(); ++i) {
if (gc_prologue_callbacks_[i].callback == callback) {
gc_prologue_callbacks_.Remove(i);
return;
}
}
UNREACHABLE();
}
void Heap::AddGCEpilogueCallback(GCEpilogueCallback callback, GCType gc_type) {
ASSERT(callback != NULL);
GCEpilogueCallbackPair pair(callback, gc_type);
ASSERT(!gc_epilogue_callbacks_.Contains(pair));
return gc_epilogue_callbacks_.Add(pair);
}
void Heap::RemoveGCEpilogueCallback(GCEpilogueCallback callback) {
ASSERT(callback != NULL);
for (int i = 0; i < gc_epilogue_callbacks_.length(); ++i) {
if (gc_epilogue_callbacks_[i].callback == callback) {
gc_epilogue_callbacks_.Remove(i);
return;
}
}
UNREACHABLE();
}
#ifdef DEBUG
class PrintHandleVisitor: public ObjectVisitor {

View File

@ -674,10 +674,20 @@ class Heap : public AllStatic {
static bool GarbageCollectionGreedyCheck();
#endif
static void AddGCPrologueCallback(
GCEpilogueCallback callback, GCType gc_type_filter);
static void RemoveGCPrologueCallback(GCEpilogueCallback callback);
static void AddGCEpilogueCallback(
GCEpilogueCallback callback, GCType gc_type_filter);
static void RemoveGCEpilogueCallback(GCEpilogueCallback callback);
static void SetGlobalGCPrologueCallback(GCCallback callback) {
ASSERT((callback == NULL) ^ (global_gc_prologue_callback_ == NULL));
global_gc_prologue_callback_ = callback;
}
static void SetGlobalGCEpilogueCallback(GCCallback callback) {
ASSERT((callback == NULL) ^ (global_gc_epilogue_callback_ == NULL));
global_gc_epilogue_callback_ = callback;
}
@ -1046,6 +1056,30 @@ class Heap : public AllStatic {
// 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) {
}
bool operator==(const GCPrologueCallbackPair& pair) const {
return pair.callback == callback;
}
GCPrologueCallback callback;
GCType gc_type;
};
static List<GCPrologueCallbackPair> gc_prologue_callbacks_;
struct GCEpilogueCallbackPair {
GCEpilogueCallbackPair(GCEpilogueCallback callback, GCType gc_type)
: callback(callback), gc_type(gc_type) {
}
bool operator==(const GCEpilogueCallbackPair& pair) const {
return pair.callback == callback;
}
GCEpilogueCallback callback;
GCType gc_type;
};
static List<GCEpilogueCallbackPair> gc_epilogue_callbacks_;
static GCCallback global_gc_prologue_callback_;
static GCCallback global_gc_epilogue_callback_;
@ -1588,6 +1622,7 @@ class GCTracer BASE_EMBEDDED {
// Sets the flag that this is a compacting full GC.
void set_is_compacting() { is_compacting_ = true; }
bool is_compacting() const { return is_compacting_; }
// Increment and decrement the count of marked objects.
void increment_marked_count() { ++marked_count_; }

View File

@ -9956,3 +9956,57 @@ TEST(Bug618) {
CHECK_EQ(23, c1->Get(v8_str("y"))->Int32Value());
}
}
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) {
++prologue_call_count;
}
void EpilogueCallback(v8::GCType, v8::GCCallbackFlags) {
++epilogue_call_count;
}
void PrologueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
++prologue_call_count_second;
}
void EpilogueCallbackSecond(v8::GCType, v8::GCCallbackFlags) {
++epilogue_call_count_second;
}
TEST(GCCallbacks) {
LocalContext context;
v8::V8::AddGCPrologueCallback(PrologueCallback);
v8::V8::AddGCEpilogueCallback(EpilogueCallback);
CHECK_EQ(0, prologue_call_count);
CHECK_EQ(0, epilogue_call_count);
i::Heap::CollectAllGarbage(false);
CHECK_EQ(1, prologue_call_count);
CHECK_EQ(1, epilogue_call_count);
v8::V8::AddGCPrologueCallback(PrologueCallbackSecond);
v8::V8::AddGCEpilogueCallback(EpilogueCallbackSecond);
i::Heap::CollectAllGarbage(false);
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);
v8::V8::RemoveGCPrologueCallback(PrologueCallback);
v8::V8::RemoveGCEpilogueCallback(EpilogueCallback);
i::Heap::CollectAllGarbage(false);
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);
v8::V8::RemoveGCPrologueCallback(PrologueCallbackSecond);
v8::V8::RemoveGCEpilogueCallback(EpilogueCallbackSecond);
i::Heap::CollectAllGarbage(false);
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);
}