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

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: Created 6 years, 4 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..5e17013c7faf82ed97e745fffa887dd862ed4d49 100644
--- a/Source/platform/heap/Handle.h
+++ b/Source/platform/heap/Handle.h
@@ -150,6 +150,207 @@ private:
friend class ThreadState;
};
+
+const int wrapperPersistentsPerRegion = 256;
+const size_t wrapperPersistentOffsetMask = ~static_cast<size_t>(3);
+const size_t wrapperPersistentLiveBitMask = 1;
+
+class WrapperPersistentNode {
+public:
+ explicit WrapperPersistentNode(const WrapperPersistentNode& otherref)
+ {
+ WrapperPersistentNode* other = const_cast<WrapperPersistentNode*>(&otherref);
+ m_raw = other->m_raw;
+ m_offset = other->m_offset;
+ }
+
+ bool isAlive() { return m_offset & wrapperPersistentLiveBitMask; }
+
+ WrapperPersistentRegion* region()
+ {
+ return reinterpret_cast<WrapperPersistentRegion*>(
+ reinterpret_cast<Address>(this) - (m_offset & wrapperPersistentOffsetMask));
+ }
+
+ virtual ~WrapperPersistentNode()
+ {
+ m_offset &= ~wrapperPersistentLiveBitMask;
+ }
+
+ virtual void trace(Visitor* visitor) { }
haraken 2014/09/02 05:22:05 You won't need this. You can just define non-virtu
wibling-chromium 2014/09/02 11:19:37 I do need this, since I am calling m_entries[i].tr
+
+protected:
+ WrapperPersistentNode() : m_raw(0), m_offset(0) { }
+
+ explicit WrapperPersistentNode(void* raw)
+ {
haraken 2014/09/02 05:22:05 Can we add ASSERT(!m_raw) ?
wibling-chromium 2014/09/02 11:19:37 Done.
+ m_raw = raw;
+ m_offset |= wrapperPersistentLiveBitMask;
zerny-chromium 2014/09/01 14:13:37 m_offset is uninitialized here. Maybe just m_offse
wibling-chromium 2014/09/02 11:19:37 m_offset has already been initialized here to have
+ }
+
+ WrapperPersistentNode(size_t offset, WrapperPersistentNode* nextFree)
+ {
+ ASSERT(!(offset & ~wrapperPersistentOffsetMask));
+ m_raw = reinterpret_cast<void*>(nextFree);
+ m_offset = offset;
+ }
+
+protected:
+ void* m_raw;
Mads Ager (chromium) 2014/09/01 13:52:46 Add a comment that m_raw is used to chain freelist
wibling-chromium 2014/09/02 11:19:38 Done.
+
+private:
+ size_t m_offset;
haraken 2014/09/02 05:22:05 m_offset => m_region or m_regionHead
haraken 2014/09/02 05:22:05 Add a comment about the memory structure of m_offs
wibling-chromium 2014/09/02 11:19:37 Changed it to m_regionOffset.
wibling-chromium 2014/09/02 11:19:37 Done.
+
+ friend class WrapperPersistentRegion;
+};
+
+template<typename T>
+class WrapperPersistent : public WrapperPersistentNode {
haraken 2014/09/02 05:22:05 Add FINAL.
wibling-chromium 2014/09/02 11:19:37 Done.
+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 {
+public:
+ WrapperPersistentRegion()
+ {
+ WrapperPersistentNode* nextFree = 0;
+ for (int i = wrapperPersistentsPerRegion-1; i >= 0; --i) {
Mads Ager (chromium) 2014/09/01 13:52:46 Nit: space around '-'
wibling-chromium 2014/09/02 11:19:37 Done.
+ size_t offset = reinterpret_cast<Address>(&m_entries[i]) - reinterpret_cast<Address>(this);
+ new (&m_entries[i]) WrapperPersistentNode(offset, nextFree);
+ nextFree = &m_entries[i];
+ }
+ m_prev = 0;
+ m_next = 0;
+ m_free = nextFree;
+ m_count = 0;
+ }
+
+ void* allocate()
Erik Corry 2014/09/01 13:40:41 I think you want this to be inlined, and you expec
wibling-chromium 2014/09/02 11:19:38 Done.
+ {
+ if (m_free) {
+ // We have a free persistent in this region.
+ WrapperPersistentNode* free = m_free;
+ m_free = reinterpret_cast<WrapperPersistentNode*>(free->m_raw);
Mads Ager (chromium) 2014/09/01 13:52:46 Maybe wrap this in a method: free->nextFree(). Th
wibling-chromium 2014/09/02 11:19:37 I have added a takeSlot and freeSlot method in add
+ free->m_raw = 0;
+ m_count++;
+ return reinterpret_cast<void*>(free);
+ }
+ // Otherwise try next region if one exists.
+ if (m_next)
+ return m_next->allocate();
Mads Ager (chromium) 2014/09/01 13:52:46 Can we use iteration iteration from the outside in
wibling-chromium 2014/09/02 11:19:37 Done.
+ return 0;
+ }
+
+ void free(WrapperPersistentNode* object)
+ {
+ ASSERT(object);
+ ASSERT(!object->isAlive());
+ object->m_raw = m_free;
+ m_free = object;
+ m_count--;
+ if (!m_count)
+ ThreadState::current()->removeWrapperPersistentRegion(this);
+ }
+
+ void trace(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++;
+ }
+ }
+ if (m_next)
+ m_next->trace(visitor);
Mads Ager (chromium) 2014/09/01 13:52:46 Can we use iteration from the outside instead of r
wibling-chromium 2014/09/02 11:19:37 Done.
+ }
+
+ size_t count() const { return m_count; }
+
+ bool removeIfNotLast(WrapperPersistentRegion** headPtr)
haraken 2014/09/02 05:22:05 Shall we move not-performance-sensitive methods to
wibling-chromium 2014/09/02 11:19:38 Done.
+ {
+ // We are the last region in the list if both the region's m_prev and
+ // m_next are 0.
+ if (m_prev == 0 && m_next == 0)
+ return false;
+ if (m_prev) {
haraken 2014/09/02 05:22:05 Can we just call removeHead() here?
wibling-chromium 2014/09/02 11:19:37 No, that is always removing the head entry via the
+ m_prev->m_next = m_next;
+ } else {
+ ASSERT(*headPtr == this);
+ *headPtr = m_next;
+ }
+ if (m_next)
+ m_next->m_prev = m_prev;
+ m_prev = 0;
+ m_next = 0;
+ return true;
+ }
+
+ static void insertHead(WrapperPersistentRegion** headPtr, WrapperPersistentRegion* newHead)
+ {
+ ASSERT(headPtr);
+ WrapperPersistentRegion* oldHead = *headPtr;
+ if (oldHead) {
+ ASSERT(!oldHead->m_prev);
+ oldHead->m_prev = newHead;
+ }
+ newHead->m_prev = 0;
+ newHead->m_next = oldHead;
+ *headPtr = newHead;
+ }
+
+ static WrapperPersistentRegion* removeHead(WrapperPersistentRegion** headPtr)
+ {
+ // We only call this if there is at least one element in the list.
+ ASSERT(headPtr && *headPtr);
+ WrapperPersistentRegion* oldHead = *headPtr;
+ ASSERT(!oldHead->m_prev);
+ *headPtr = oldHead->m_next;
+ oldHead->m_next = 0;
+ ASSERT(!(*headPtr) || (*headPtr)->m_prev == oldHead);
+ if (*headPtr)
+ (*headPtr)->m_prev = 0;
+ return oldHead;
+ }
+
+private:
+ WrapperPersistentRegion* m_prev;
+ WrapperPersistentRegion* m_next;
haraken 2014/09/02 05:22:05 Shall we override 'operator new=' in a private sec
wibling-chromium 2014/09/02 11:19:37 Are you referring to the assignment operator? If s
+ WrapperPersistentNode* m_free;
+ size_t m_count;
+ WrapperPersistentNode m_entries[wrapperPersistentsPerRegion];
+};
+
+template<typename T>
+void* WrapperPersistent<T>::operator new(size_t size)
+{
+ ThreadState* state = ThreadState::current();
+ WrapperPersistentRegion* region = state->wrapperRoots();
+ void* persistent = region->allocate();
+ if (!persistent) {
+ region = state->addWrapperPersistentRegion();
+ persistent = region->allocate();
+ }
+ ASSERT(persistent);
+ 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