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:
parent
b278895d28
commit
4d1f8cbfd6
62
include/v8.h
62
include/v8.h
@ -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
|
||||
|
24
src/api.cc
24
src/api.cc
@ -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);
|
||||
|
62
src/heap.cc
62
src/heap.cc
@ -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 {
|
||||
|
35
src/heap.h
35
src/heap.h
@ -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_; }
|
||||
|
@ -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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user