/* * Copyright (C) 2014 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 Chunk_h #define Chunk_h #include "Object.h" #include "Sizes.h" #include "SmallLine.h" #include "SmallPage.h" #include "VMAllocate.h" #include namespace bmalloc { class Chunk : public ListNode { public: static Chunk* get(void*); static size_t metadataSize(size_t pageSize); Chunk(size_t pageSize); void ref() { ++m_refCount; } void deref() { BASSERT(m_refCount); --m_refCount; } unsigned refCount() { return m_refCount; } size_t offset(void*); char* address(size_t offset); SmallPage* page(size_t offset); SmallLine* line(size_t offset); char* bytes() { return reinterpret_cast(this); } SmallLine* lines() { return &m_lines[0]; } SmallPage* pages() { return &m_pages[0]; } List& freePages() { return m_freePages; } private: size_t m_refCount { }; List m_freePages { }; std::array m_lines { }; std::array m_pages { }; }; struct ChunkHash { static unsigned hash(Chunk* key) { return static_cast( reinterpret_cast(key) / chunkSize); } }; inline size_t Chunk::metadataSize(size_t pageSize) { // We align to at least the page size so we can service aligned allocations // at equal and smaller powers of two, and also so we can vmDeallocatePhysicalPages(). return roundUpToMultipleOfNonPowerOfTwo(pageSize, sizeof(Chunk)); } template void forEachPage(Chunk* chunk, size_t pageSize, Function function) { Object begin(chunk, Chunk::metadataSize(pageSize)); Object end(chunk, chunkSize); for (auto it = begin; it + pageSize <= end; it = it + pageSize) function(it.page()); } inline Chunk::Chunk(size_t pageSize) { size_t smallPageCount = pageSize / smallPageSize; forEachPage(this, pageSize, [&](SmallPage* page) { for (size_t i = 0; i < smallPageCount; ++i) page[i].setSlide(i); }); } inline Chunk* Chunk::get(void* address) { return static_cast(mask(address, chunkMask)); } inline size_t Chunk::offset(void* address) { BASSERT(address >= this); BASSERT(address < bytes() + chunkSize); return static_cast(address) - bytes(); } inline char* Chunk::address(size_t offset) { return bytes() + offset; } inline SmallPage* Chunk::page(size_t offset) { size_t pageNumber = offset / smallPageSize; SmallPage* page = &m_pages[pageNumber]; return page - page->slide(); } inline SmallLine* Chunk::line(size_t offset) { size_t lineNumber = offset / smallLineSize; return &m_lines[lineNumber]; } inline char* SmallLine::begin() { Chunk* chunk = Chunk::get(this); size_t lineNumber = this - chunk->lines(); size_t offset = lineNumber * smallLineSize; return &reinterpret_cast(chunk)[offset]; } inline char* SmallLine::end() { return begin() + smallLineSize; } inline SmallLine* SmallPage::begin() { BASSERT(!m_slide); Chunk* chunk = Chunk::get(this); size_t pageNumber = this - chunk->pages(); size_t lineNumber = pageNumber * smallPageLineCount; return &chunk->lines()[lineNumber]; } inline Object::Object(void* object) : m_chunk(Chunk::get(object)) , m_offset(m_chunk->offset(object)) { } inline Object::Object(Chunk* chunk, void* object) : m_chunk(chunk) , m_offset(m_chunk->offset(object)) { BASSERT(chunk == Chunk::get(object)); } inline char* Object::address() { return m_chunk->address(m_offset); } inline SmallLine* Object::line() { return m_chunk->line(m_offset); } inline SmallPage* Object::page() { return m_chunk->page(m_offset); } }; // namespace bmalloc #endif // Chunk