From 9dc2c5b83dfcf9abb68bceccf0c11c0e96688037 Mon Sep 17 00:00:00 2001 From: "svenpanne@chromium.org" Date: Thu, 18 Oct 2012 06:52:37 +0000 Subject: [PATCH] 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 . git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@12750 ce2b1a6d-e550-0410-aec6-3dcde31c8c00 --- include/v8.h | 52 +++++++++++++++++++++++++++++++++++++++++-------- src/api.cc | 37 +++++++++++++++++++++++++++++++++++ src/global-handles.cc | 8 ++++++++ src/global-handles.h | 3 +++ test/cctest/test-api.cc | 39 +++++++++++++++++++++++++++++++++++++ 5 files changed, 131 insertions(+), 8 deletions(-) diff --git a/include/v8.h b/include/v8.h index ff44fdf..448aaa1 100644 --- a/include/v8.h +++ b/include/v8.h @@ -390,7 +390,7 @@ template class Persistent : public Handle { */ 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 Persistent : public Handle { */ 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 Persistent : public Handle { */ 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, + 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 friend class Handle; template friend class Local; @@ -4186,6 +4210,13 @@ Persistent Persistent::New(Handle that) { template +bool Persistent::IsIndependent() const { + if (this->IsEmpty()) return false; + return V8::IsGlobalIndependent(reinterpret_cast(**this)); +} + + +template bool Persistent::IsNearDeath() const { if (this->IsEmpty()) return false; return V8::IsGlobalNearDeath(reinterpret_cast(**this)); @@ -4231,6 +4262,11 @@ void Persistent::SetWrapperClassId(uint16_t class_id) { V8::SetWrapperClassId(reinterpret_cast(**this), class_id); } +template +uint16_t Persistent::WrapperClassId() const { + return V8::GetWrapperClassId(reinterpret_cast(**this)); +} + Arguments::Arguments(internal::Object** implicit_args, internal::Object** values, int length, bool is_construct_call) diff --git a/src/api.cc b/src/api.cc index dcadf52..426f53e 100644 --- a/src/api.cc +++ b/src/api.cc @@ -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(i::Handle(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 ObjectTemplate::NewInstance() { i::Isolate* isolate = i::Isolate::Current(); ON_BAILOUT(isolate, "v8::ObjectTemplate::NewInstance()", diff --git a/src/global-handles.cc b/src/global-handles.cc index 9c0ad45..c09ba4b 100644 --- a/src/global-handles.cc +++ b/src/global-handles.cc @@ -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()) { diff --git a/src/global-handles.h b/src/global-handles.h index ddf5fe2..866317e 100644 --- a/src/global-handles.h +++ b/src/global-handles.h @@ -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); diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc index a8f340d..7815188 100644 --- a/test/cctest/test-api.cc +++ b/test/cctest/test-api.cc @@ -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 object = + v8::Persistent::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 object) + : counter_(0), object_(object) { } + + virtual void VisitPersistentHandle(Persistent value, + uint16_t class_id) { + if (class_id == 42) { + CHECK(value->IsObject()); + v8::Persistent visited = + v8::Persistent::Cast(value); + CHECK_EQ(42, visited.WrapperClassId()); + CHECK_EQ(object_, visited); + ++counter_; + } + } + + int counter_; + v8::Persistent object_; + } visitor(object); + + v8::V8::VisitHandlesWithClassIds(&visitor); + CHECK_EQ(1, visitor.counter_); + + object.Dispose(); +} + + TEST(RegExp) { v8::HandleScope scope; LocalContext context; -- 2.7.4