Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1847)

Unified Diff: Source/platform/heap/Handle.h

Issue 556823003: Revert "Revert of [oilpan]: optimize the way we allocate persistent handles in wrappers. (patchset … (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: review feedback Created 6 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « Source/platform/heap/BUILD.gn ('k') | Source/platform/heap/Handle.cpp » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: Source/platform/heap/Handle.h
diff --git a/Source/platform/heap/Handle.h b/Source/platform/heap/Handle.h
index 62c7734053274e02f73723c59bfffb6f39cc9841..277b9f7b6bea525d10879b3a9ec41fab7e1ee64e 100644
--- a/Source/platform/heap/Handle.h
+++ b/Source/platform/heap/Handle.h
@@ -150,6 +150,199 @@ private:
friend class ThreadState;
};
+
+const int wrapperPersistentsPerRegion = 256;
+const size_t wrapperPersistentOffsetMask = ~static_cast<size_t>(3);
+const size_t wrapperPersistentLiveBitMask = 1;
+
+class WrapperPersistentNode {
+ ALLOW_ONLY_INLINE_ALLOCATION();
+ WTF_MAKE_NONCOPYABLE(WrapperPersistentNode);
+public:
+ bool isAlive() { return m_regionOffset & wrapperPersistentLiveBitMask; }
+
+ WrapperPersistentRegion* region()
+ {
+ return reinterpret_cast<WrapperPersistentRegion*>(
+ reinterpret_cast<Address>(this) - regionOffset());
+ }
+
+ virtual void trace(Visitor* visitor) { }
+
+ static inline void destroy(const WrapperPersistentNode*);
+
+protected:
+ WrapperPersistentNode() : m_raw(0), m_regionOffset(0) { }
+ WrapperPersistentNode(void *raw, size_t regionOffset) : m_raw(raw), m_regionOffset(regionOffset) { }
+
+private:
+ size_t regionOffset() { return m_regionOffset & wrapperPersistentOffsetMask; }
+
+ WrapperPersistentNode* takeSlot()
+ {
+ // The slot should not be alive at the point where it is allocated.
+ ASSERT(!isAlive());
+ WrapperPersistentNode* nextFree = reinterpret_cast<WrapperPersistentNode*>(m_raw);
+ m_raw = 0;
+ return nextFree;
+ }
+
+ WrapperPersistentNode* freeSlot(WrapperPersistentNode* nextFree)
+ {
+ m_regionOffset &= ~wrapperPersistentLiveBitMask;
+ m_raw = nextFree;
+ return this;
+ }
+
+ // Don't allow delete being called on wrapper persistent nodes. We
+ // do use placement new to initialize the slot with the right vtable. See
+ // WrapperPersistent<T> below.
+ void operator delete(void*);
+
+protected:
+ // m_raw is used both to point to the object when the WrapperPersistentNode is used/alive
+ // and to point to the next free wrapperPersistentNode in the region when the node is
+ // unused/dead.
+ void* m_raw;
+
+ // The m_regionOffset field encodes liveness of the slot as well as being an
+ // offset from this node to the base of the containing WrapperPersistentRegion.
+ size_t m_regionOffset;
+
+ friend class WrapperPersistentRegion;
+};
+
+template<typename T>
+class WrapperPersistent FINAL : public WrapperPersistentNode {
+ ALLOW_ONLY_INLINE_ALLOCATION();
+public:
+ static WrapperPersistent<T>* create(T* raw);
+
+ virtual void trace(Visitor* visitor) OVERRIDE
+ {
+ ASSERT(isAlive());
+ visitor->mark(static_cast<T*>(m_raw));
+ }
+
+private:
+ WrapperPersistent() { }
+
+ // We need to use a constructor to initialize the allocated slot since it
+ // has a vtable which must be set to the WrapperPersistent<T> type.
+ WrapperPersistent(T* raw, size_t regionOffset) : WrapperPersistentNode(raw, regionOffset) { }
+
+ // Don't allow delete being called on wrapper persistents.
+ void operator delete(void*);
+};
+
+class PLATFORM_EXPORT WrapperPersistentRegion {
+ WTF_MAKE_NONCOPYABLE(WrapperPersistentRegion);
+public:
+ WrapperPersistentRegion()
+ {
+ WrapperPersistentNode* nextFree = 0;
+ for (int i = wrapperPersistentsPerRegion - 1; i >= 0; --i) {
+ size_t regionOffset = reinterpret_cast<Address>(&m_entries[i]) - reinterpret_cast<Address>(this);
+ // Setup the free slot with an offset to the containing region's base and a pointer to the next
+ // free slot in the region.
+ ASSERT(!(regionOffset & ~wrapperPersistentOffsetMask));
+ new (&m_entries[i]) WrapperPersistentNode(nextFree, regionOffset);
+ nextFree = &m_entries[i];
+ }
+ m_prev = 0;
+ m_next = 0;
+ m_freeHead = nextFree;
+ m_count = 0;
+ }
+
+ Address allocate()
+ {
+ if (!m_freeHead) {
+ ASSERT(m_count == wrapperPersistentsPerRegion);
+ return 0;
+ }
+ // We have a free persistent slot in this region.
+ WrapperPersistentNode* freeSlot = m_freeHead;
+ // Take the slot and advance m_freeHead to the next free slot.
+ m_freeHead = freeSlot->takeSlot();
+ ASSERT(m_count < wrapperPersistentsPerRegion);
+ m_count++;
+ return reinterpret_cast<Address>(freeSlot);
+ }
+
+ void free(WrapperPersistentNode* object)
+ {
+ ASSERT(object);
+ m_freeHead = object->freeSlot(m_freeHead);
+ ASSERT(m_count > 0);
+ m_count--;
+ if (!m_count)
+ ThreadState::current()->freeWrapperPersistentRegion(this);
+ }
+
+ bool removeIfNotLast(WrapperPersistentRegion** headPtr);
+ static void insertHead(WrapperPersistentRegion** headPtr, WrapperPersistentRegion* newHead);
+ static WrapperPersistentRegion* removeHead(WrapperPersistentRegion** headPtr);
+ static Address outOfLineAllocate(ThreadState*, WrapperPersistentRegion**);
+ static void trace(WrapperPersistentRegion* head, Visitor* visitor)
+ {
+ for (WrapperPersistentRegion* current = head; current; current = current->m_next)
+ current->traceRegion(visitor);
+ }
+
+private:
+ void traceRegion(Visitor* visitor)
+ {
+ size_t live = 0;
+
+#ifdef NDEBUG
+ for (int i = 0; i < wrapperPersistentsPerRegion && live < m_count; ++i) {
+#else
+ // In DEBUG mode we scan all entries to validate we only have m_count
+ // live entries.
+ for (int i = 0; i < wrapperPersistentsPerRegion; ++i) {
+#endif
+ if (m_entries[i].isAlive()) {
+ m_entries[i].trace(visitor);
+ live++;
+ }
+ }
+ ASSERT(live == m_count);
+ }
+
+ WrapperPersistentRegion* m_prev;
+ WrapperPersistentRegion* m_next;
+ WrapperPersistentNode* m_freeHead;
+ size_t m_count;
+ WrapperPersistentNode m_entries[wrapperPersistentsPerRegion];
+};
+
+template<typename T>
+WrapperPersistent<T>* WrapperPersistent<T>::create(T* raw)
+{
+ ThreadState* state = ThreadState::current();
+ WrapperPersistentRegion* region = state->wrapperRoots();
+ ASSERT(region);
+ Address persistentSlot = region->allocate();
+ if (!persistentSlot)
+ persistentSlot = WrapperPersistentRegion::outOfLineAllocate(state, &region);
+ ASSERT(persistentSlot);
+ ASSERT(!reinterpret_cast<WrapperPersistentNode*>(persistentSlot)->isAlive());
+
+ size_t regionOffset = persistentSlot - reinterpret_cast<Address>(region);
+ regionOffset |= wrapperPersistentLiveBitMask;
+
+ // We use placement new to call the constructor to ensure that we setup the
+ // vtable correctly.
+ return new (persistentSlot) WrapperPersistent<T>(raw, regionOffset);
+}
+
+void WrapperPersistentNode::destroy(const WrapperPersistentNode* node)
+{
+ WrapperPersistentNode* persistent = const_cast<WrapperPersistentNode*>(node);
+ persistent->region()->free(persistent);
+}
+
// RootsAccessor for Persistent that provides access to thread-local list
// of persistent handles. Can only be used to create handles that
// are constructed and destructed on the same thread.
« no previous file with comments | « Source/platform/heap/BUILD.gn ('k') | Source/platform/heap/Handle.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698