Add an API for enumerating persistent handles
authorsvenpanne@chromium.org <svenpanne@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 18 Oct 2012 06:52:37 +0000 (06:52 +0000)
committersvenpanne@chromium.org <svenpanne@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Thu, 18 Oct 2012 06:52:37 +0000 (06:52 +0000)
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

include/v8.h
src/api.cc
src/global-handles.cc
src/global-handles.h
test/cctest/test-api.cc

index ff44fdf..448aaa1 100644 (file)
@@ -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:
@@ -3021,6 +3026,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.
  */
 class V8EXPORT V8 {
@@ -3428,6 +3444,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.
    * This call can be used repeatedly if the embedder remains idle.
@@ -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;
@@ -4186,6 +4210,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;
   return V8::IsGlobalNearDeath(reinterpret_cast<internal::Object**>(**this));
@@ -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)
index dcadf52..426f53e 100644 (file)
@@ -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()",
index 9c0ad45..c09ba4b 100644 (file)
@@ -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()) {
index ddf5fe2..866317e 100644 (file)
@@ -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);
 
index a8f340d..7815188 100644 (file)
@@ -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;