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

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

Issue 525353002: [oilpan]: optimize the way we allocate persistent handles in wrappers. (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: short copyright header 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
Index: Source/platform/heap/Handle.h
diff --git a/Source/platform/heap/Handle.h b/Source/platform/heap/Handle.h
index 62c7734053274e02f73723c59bfffb6f39cc9841..3cf1dca4bea5fa21d4826c6a03dd2e5b53668f63 100644
--- a/Source/platform/heap/Handle.h
+++ b/Source/platform/heap/Handle.h
@@ -150,6 +150,189 @@ private:
friend class ThreadState;
};
+
+const int wrapperPersistentsPerRegion = 256;
+const size_t wrapperPersistentOffsetMask = ~static_cast<size_t>(3);
+const size_t wrapperPersistentLiveBitMask = 1;
+
+class WrapperPersistentNode {
+ WTF_MAKE_NONCOPYABLE(WrapperPersistentNode);
+public:
+ bool isAlive() { return m_regionOffset & wrapperPersistentLiveBitMask; }
+
+ WrapperPersistentRegion* region()
+ {
+ return reinterpret_cast<WrapperPersistentRegion*>(
+ reinterpret_cast<Address>(this) - (m_regionOffset & wrapperPersistentOffsetMask));
+ }
+
+ virtual ~WrapperPersistentNode()
+ {
+ m_regionOffset &= ~wrapperPersistentLiveBitMask;
+ }
+
+ virtual void trace(Visitor* visitor) { }
+
+protected:
+ WrapperPersistentNode() : m_raw(0), m_regionOffset(0) { }
+
+ explicit WrapperPersistentNode(void* raw)
+ {
+ // When the constructor is called the slot should have been taken (takeSlot)
+ // as part of allocating the memory (via operator new). Hence the m_raw
+ // pointer should be 0.
+ ASSERT(!m_raw);
+ m_raw = raw;
+ // The m_regionOffset should always be set as an offset to the containing
+ // region. However it should not have the live bit set when the constructor
+ // is called.
+ ASSERT(m_regionOffset && !isAlive());
+ m_regionOffset |= wrapperPersistentLiveBitMask;
haraken 2014/09/02 13:00:37 m_regionOffset = wrapperPersistentLiveBitMask; ?
wibling-chromium 2014/09/02 13:55:33 No, since the offset to the base is already in the
+ }
+
+private:
+ void initSlot(size_t regionOffset, WrapperPersistentNode* nextFree)
+ {
+ ASSERT(!m_raw);
+ ASSERT(!m_regionOffset);
+ ASSERT(!(regionOffset & ~wrapperPersistentOffsetMask));
+ m_raw = nextFree;
+ m_regionOffset = regionOffset;
+ }
+
+ 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)
+ {
+ // When the slot is freed the destructor should already have cleared the live bit.
+ ASSERT(!isAlive());
+ m_raw = nextFree;
+ return this;
+ }
+
+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 is 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 {
+public:
+ WrapperPersistent() : WrapperPersistentNode(0) { }
+ WrapperPersistent(std::nullptr_t) : WrapperPersistentNode(0) { }
+ WrapperPersistent(T* raw) : WrapperPersistentNode(raw) { }
+ WrapperPersistent(T& raw) : WrapperPersistentNode(&raw) { }
+
+ void* operator new(size_t);
+ void operator delete(void*);
+
+ virtual void trace(Visitor* visitor) { visitor->mark(static_cast<T*>(m_raw)); }
+};
+
+class 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.
+ m_entries[i].initSlot(regionOffset, nextFree);
+ nextFree = &m_entries[i];
+ }
+ m_prev = 0;
+ m_next = 0;
+ m_freeHead = nextFree;
+ m_count = 0;
+ }
+
+ void* allocate()
+ {
+ if (!m_freeHead)
+ 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();
+ m_count++;
+ return reinterpret_cast<void*>(freeSlot);
+ }
+
+ void free(WrapperPersistentNode* object)
+ {
+ ASSERT(object);
+ ASSERT(!object->isAlive());
+ m_freeHead = object->freeSlot(m_freeHead);
+ m_count--;
+ if (!m_count)
+ ThreadState::current()->removeWrapperPersistentRegion(this);
+ }
+
+ bool removeIfNotLast(WrapperPersistentRegion** headPtr);
+ static void insertHead(WrapperPersistentRegion** headPtr, WrapperPersistentRegion* newHead);
+ static WrapperPersistentRegion* removeHead(WrapperPersistentRegion** headPtr);
+ static void* 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;
+ for (int i = 0; i < wrapperPersistentsPerRegion && live < m_count; ++i) {
+ if (m_entries[i].isAlive()) {
+ m_entries[i].trace(visitor);
+ live++;
+ }
+ }
+ }
+
+ WrapperPersistentRegion* m_prev;
+ WrapperPersistentRegion* m_next;
+ WrapperPersistentNode* m_freeHead;
+ size_t m_count;
+ WrapperPersistentNode m_entries[wrapperPersistentsPerRegion];
+};
+
+template<typename T>
+void* WrapperPersistent<T>::operator new(size_t size)
haraken 2014/09/02 13:00:37 Drop |size|.
wibling-chromium 2014/09/02 13:55:32 I added an assert(size == sizeof(WrapperPersistent
+{
+ ThreadState* state = ThreadState::current();
+ WrapperPersistentRegion* region = state->wrapperRoots();
+ ASSERT(region);
+ void* persistent = region->allocate();
+ if (!persistent)
+ return WrapperPersistentRegion::outOfLineAllocate(state, region);
+ return persistent;
+}
+
+template<typename T>
+void WrapperPersistent<T>::operator delete(void* object)
+{
+ WrapperPersistentNode* persistent = static_cast<WrapperPersistentNode*>(object);
+ 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.

Powered by Google App Engine
This is Rietveld 408576698