Add an API for enumerating persistent handles

This API lets the embedder enumerate handles that have class ids. WebKit will
use this feature during garbage collection to compute object groups for DOM
nodes. Previously, we kept a list of DOM nodes on the WebKit side, but that
list is redundant with the global handles list in V8.

Review URL: https://codereview.chromium.org/11190011
Patch from Adam Barth <abarth@chromium.org>.

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@12750 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 966b0844
......@@ -390,7 +390,7 @@ template <class T> class Persistent : public Handle<T> {
*/
inline void MakeWeak(void* parameters, WeakReferenceCallback callback);
/** Clears the weak reference to this object.*/
/** Clears the weak reference to this object. */
inline void ClearWeak();
/**
......@@ -402,14 +402,13 @@ template <class T> class Persistent : public Handle<T> {
*/
inline void MarkIndependent();
/**
*Checks if the handle holds the only reference to an object.
*/
/** Returns true if this handle was previously marked as independent. */
inline bool IsIndependent() const;
/** Checks if the handle holds the only reference to an object. */
inline bool IsNearDeath() const;
/**
* Returns true if the handle's reference is weak.
*/
/** Returns true if the handle's reference is weak. */
inline bool IsWeak() const;
/**
......@@ -418,6 +417,12 @@ template <class T> class Persistent : public Handle<T> {
*/
inline void SetWrapperClassId(uint16_t class_id);
/**
* Returns the class ID previously assigned to this handle or 0 if no class
* ID was previously assigned.
*/
inline uint16_t WrapperClassId() const;
private:
friend class ImplementationUtilities;
friend class ObjectTemplate;
......@@ -3011,7 +3016,7 @@ typedef void (*JitCodeEventHandler)(const JitCodeEvent* event);
/**
* Interface for iterating though all external resources in the heap.
* Interface for iterating through all external resources in the heap.
*/
class V8EXPORT ExternalResourceVisitor { // NOLINT
public:
......@@ -3020,6 +3025,17 @@ class V8EXPORT ExternalResourceVisitor { // NOLINT
};
/**
* Interface for iterating through all the persistent handles in the heap.
*/
class V8EXPORT PersistentHandleVisitor { // NOLINT
public:
virtual ~PersistentHandleVisitor() {}
virtual void VisitPersistentHandle(Persistent<Value> value,
uint16_t class_id) {}
};
/**
* Container class for static utility functions.
*/
......@@ -3427,6 +3443,12 @@ class V8EXPORT V8 {
*/
static void VisitExternalResources(ExternalResourceVisitor* visitor);
/**
* Iterates through all the persistent handles in the current isolate's heap
* that have class_ids.
*/
static void VisitHandlesWithClassIds(PersistentHandleVisitor* visitor);
/**
* Optional notification that the embedder is idle.
* V8 uses the notification to reduce memory footprint.
......@@ -3465,10 +3487,12 @@ class V8EXPORT V8 {
WeakReferenceCallback);
static void ClearWeak(internal::Object** global_handle);
static void MarkIndependent(internal::Object** global_handle);
static bool IsGlobalIndependent(internal::Object** global_handle);
static bool IsGlobalNearDeath(internal::Object** global_handle);
static bool IsGlobalWeak(internal::Object** global_handle);
static void SetWrapperClassId(internal::Object** global_handle,
uint16_t class_id);
static uint16_t GetWrapperClassId(internal::Object** global_handle);
template <class T> friend class Handle;
template <class T> friend class Local;
......@@ -4185,6 +4209,13 @@ Persistent<T> Persistent<T>::New(Handle<T> that) {
}
template <class T>
bool Persistent<T>::IsIndependent() const {
if (this->IsEmpty()) return false;
return V8::IsGlobalIndependent(reinterpret_cast<internal::Object**>(**this));
}
template <class T>
bool Persistent<T>::IsNearDeath() const {
if (this->IsEmpty()) return false;
......@@ -4231,6 +4262,11 @@ void Persistent<T>::SetWrapperClassId(uint16_t class_id) {
V8::SetWrapperClassId(reinterpret_cast<internal::Object**>(**this), class_id);
}
template <class T>
uint16_t Persistent<T>::WrapperClassId() const {
return V8::GetWrapperClassId(reinterpret_cast<internal::Object**>(**this));
}
Arguments::Arguments(internal::Object** implicit_args,
internal::Object** values, int length,
bool is_construct_call)
......
......@@ -648,6 +648,14 @@ void V8::MarkIndependent(i::Object** object) {
}
bool V8::IsGlobalIndependent(i::Object** obj) {
i::Isolate* isolate = i::Isolate::Current();
LOG_API(isolate, "IsGlobalIndependent");
if (!isolate->IsInitialized()) return false;
return i::GlobalHandles::IsIndependent(obj);
}
bool V8::IsGlobalNearDeath(i::Object** obj) {
i::Isolate* isolate = i::Isolate::Current();
LOG_API(isolate, "IsGlobalNearDeath");
......@@ -4336,6 +4344,30 @@ void v8::V8::VisitExternalResources(ExternalResourceVisitor* visitor) {
}
void v8::V8::VisitHandlesWithClassIds(PersistentHandleVisitor* visitor) {
i::Isolate* isolate = i::Isolate::Current();
IsDeadCheck(isolate, "v8::V8::VisitHandlesWithClassId");
i::AssertNoAllocation no_allocation;
class VisitorAdapter : public i::ObjectVisitor {
public:
explicit VisitorAdapter(PersistentHandleVisitor* visitor)
: visitor_(visitor) {}
virtual void VisitPointers(i::Object** start, i::Object** end) {
UNREACHABLE();
}
virtual void VisitEmbedderReference(i::Object** p, uint16_t class_id) {
visitor_->VisitPersistentHandle(ToApi<Value>(i::Handle<i::Object>(p)),
class_id);
}
private:
PersistentHandleVisitor* visitor_;
} visitor_adapter(visitor);
isolate->global_handles()->IterateAllRootsWithClassIds(&visitor_adapter);
}
bool v8::V8::IdleNotification(int hint) {
// Returning true tells the caller that it need not
// continue to call IdleNotification.
......@@ -4620,6 +4652,11 @@ void V8::SetWrapperClassId(i::Object** global_handle, uint16_t class_id) {
}
uint16_t V8::GetWrapperClassId(internal::Object** global_handle) {
return i::GlobalHandles::GetWrapperClassId(global_handle);
}
Local<v8::Object> ObjectTemplate::NewInstance() {
i::Isolate* isolate = i::Isolate::Current();
ON_BAILOUT(isolate, "v8::ObjectTemplate::NewInstance()",
......
......@@ -448,6 +448,11 @@ void GlobalHandles::MarkIndependent(Object** location) {
}
bool GlobalHandles::IsIndependent(Object** location) {
return Node::FromLocation(location)->is_independent();
}
bool GlobalHandles::IsNearDeath(Object** location) {
return Node::FromLocation(location)->IsNearDeath();
}
......@@ -462,6 +467,9 @@ void GlobalHandles::SetWrapperClassId(Object** location, uint16_t class_id) {
Node::FromLocation(location)->set_wrapper_class_id(class_id);
}
uint16_t GlobalHandles::GetWrapperClassId(Object** location) {
return Node::FromLocation(location)->wrapper_class_id();
}
void GlobalHandles::IterateWeakRoots(ObjectVisitor* v) {
for (NodeIterator it(this); !it.done(); it.Advance()) {
......
......@@ -131,6 +131,7 @@ class GlobalHandles {
WeakReferenceCallback callback);
static void SetWrapperClassId(Object** location, uint16_t class_id);
static uint16_t GetWrapperClassId(Object** location);
// Returns the current number of weak handles.
int NumberOfWeakHandles() { return number_of_weak_handles_; }
......@@ -154,6 +155,8 @@ class GlobalHandles {
// Clear the weakness of a global handle.
void MarkIndependent(Object** location);
static bool IsIndependent(Object** location);
// Tells whether global handle is near death.
static bool IsNearDeath(Object** location);
......
......@@ -5229,7 +5229,9 @@ THREADED_TEST(IndependentWeakHandle) {
bool object_a_disposed = false;
object_a.MakeWeak(&object_a_disposed, &DisposeAndSetFlag);
CHECK(!object_a.IsIndependent());
object_a.MarkIndependent();
CHECK(object_a.IsIndependent());
HEAP->PerformScavenge();
CHECK(object_a_disposed);
}
......@@ -16177,6 +16179,43 @@ TEST(DontDeleteCellLoadICAPI) {
}
TEST(PersistentHandleVisitor) {
v8::HandleScope scope;
LocalContext context;
v8::Persistent<v8::Object> object =
v8::Persistent<v8::Object>::New(v8::Object::New());
CHECK_EQ(0, object.WrapperClassId());
object.SetWrapperClassId(42);
CHECK_EQ(42, object.WrapperClassId());
class Visitor : public v8::PersistentHandleVisitor {
public:
explicit Visitor(v8::Persistent<v8::Object> object)
: counter_(0), object_(object) { }
virtual void VisitPersistentHandle(Persistent<Value> value,
uint16_t class_id) {
if (class_id == 42) {
CHECK(value->IsObject());
v8::Persistent<v8::Object> visited =
v8::Persistent<v8::Object>::Cast(value);
CHECK_EQ(42, visited.WrapperClassId());
CHECK_EQ(object_, visited);
++counter_;
}
}
int counter_;
v8::Persistent<v8::Object> object_;
} visitor(object);
v8::V8::VisitHandlesWithClassIds(&visitor);
CHECK_EQ(1, visitor.counter_);
object.Dispose();
}
TEST(RegExp) {
v8::HandleScope scope;
LocalContext context;
......
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