summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/tools/TieredMMapArray.h
diff options
context:
space:
mode:
Diffstat (limited to 'Source/JavaScriptCore/tools/TieredMMapArray.h')
-rw-r--r--Source/JavaScriptCore/tools/TieredMMapArray.h117
1 files changed, 117 insertions, 0 deletions
diff --git a/Source/JavaScriptCore/tools/TieredMMapArray.h b/Source/JavaScriptCore/tools/TieredMMapArray.h
new file mode 100644
index 000000000..fa6e5ae1f
--- /dev/null
+++ b/Source/JavaScriptCore/tools/TieredMMapArray.h
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2012 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef TieredMMapArray_h
+#define TieredMMapArray_h
+
+#include "OSAllocator.h"
+
+namespace JSC {
+
+// This class implements a simple array class that can be grown by appending items to the end.
+// This class is implemented purely in terms of system allocations, with no malloc/free, so that
+// it can safely be used from a secondary thread whilst the main thrad is paused (potentially
+// holding the fast malloc heap lock).
+template<typename T>
+class TieredMMapArray {
+ static const size_t entriesPerBlock = 4096;
+
+public:
+ TieredMMapArray()
+ : m_directoryCount(4096)
+ , m_directory(static_cast<T**>(OSAllocator::reserveAndCommit(m_directoryCount * sizeof(T*))))
+ , m_size(0)
+ {
+ for (size_t block = 0; block < m_directoryCount; ++block)
+ m_directory[block] = 0;
+ }
+
+ ~TieredMMapArray()
+ {
+ size_t usedCount = (m_size + (entriesPerBlock - 1)) / entriesPerBlock;
+ ASSERT(usedCount == m_directoryCount || !m_directory[usedCount]);
+
+ for (size_t block = 0; block < usedCount; ++block) {
+ ASSERT(m_directory[block]);
+ OSAllocator::decommitAndRelease(m_directory[block], entriesPerBlock * sizeof(T));
+ }
+
+ OSAllocator::decommitAndRelease(m_directory, m_directoryCount * sizeof(T*));
+ }
+
+ T& operator[](size_t index)
+ {
+ ASSERT(index < m_size);
+ size_t block = index / entriesPerBlock;
+ size_t offset = index % entriesPerBlock;
+
+ ASSERT(m_directory[block]);
+ return m_directory[block][offset];
+ }
+
+ void append(const T& value)
+ {
+ // Check if the array is completely full, if so create more capacity in the directory.
+ if (m_size == m_directoryCount * entriesPerBlock) {
+ // Reallocate the directory.
+ size_t oldDirectorySize = m_directoryCount * sizeof(T*);
+ size_t newDirectorySize = oldDirectorySize * 2;
+ if (newDirectorySize < oldDirectorySize)
+ CRASH();
+ m_directory = OSAllocator::reallocateCommitted(m_directory, oldDirectorySize, newDirectorySize);
+
+ //
+ size_t newDirectoryCount = m_directoryCount * 2;
+ for (size_t block = m_directoryCount; block < newDirectoryCount; ++block)
+ m_directory[block] = 0;
+ m_directoryCount = newDirectoryCount;
+ }
+
+ size_t index = m_size;
+ size_t block = index / entriesPerBlock;
+ size_t offset = index % entriesPerBlock;
+
+ if (!offset) {
+ ASSERT(!m_directory[block]);
+ m_directory[block] = static_cast<T*>(OSAllocator::reserveAndCommit(entriesPerBlock * sizeof(T)));
+ }
+
+ ASSERT(m_directory[block]);
+ ++m_size;
+ m_directory[block][offset] = value;
+ }
+
+ size_t size() const { return m_size; }
+
+private:
+ size_t m_directoryCount;
+ T** m_directory;
+ size_t m_size;
+};
+
+}
+
+#endif // TieredMMapArray_h
+