/*
 * Copyright (C) 2017-2018 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. 
 */

#pragma once

#include "IsoDirectory.h"

namespace bmalloc {

template<typename Config>
IsoDirectoryBase<Config>::IsoDirectoryBase(IsoHeapImpl<Config>& heap)
    : m_heap(heap)
{
}

template<typename Config, unsigned passedNumPages>
IsoDirectory<Config, passedNumPages>::IsoDirectory(IsoHeapImpl<Config>& heap)
    : IsoDirectoryBase<Config>(heap)
{
    for (unsigned i = numPages; i--;)
        m_pages[i] = nullptr;
}

template<typename Config, unsigned passedNumPages>
EligibilityResult<Config> IsoDirectory<Config, passedNumPages>::takeFirstEligible()
{
    unsigned pageIndex = (m_eligible | ~m_committed).findBit(m_firstEligible, true);
    m_firstEligible = pageIndex;
    if (pageIndex >= numPages)
        return EligibilityKind::Full;

    m_highWatermark = std::max(pageIndex, m_highWatermark);
    
    Scavenger& scavenger = *PerProcess<Scavenger>::get();
    scavenger.didStartGrowing();
    
    IsoPage<Config>* page = m_pages[pageIndex];
    
    if (!m_committed[pageIndex]) {
        scavenger.scheduleIfUnderMemoryPressure(IsoPageBase::pageSize);
        
        // It could be that we haven't even allocated a page yet. Do that now!
        if (!page) {
            page = IsoPage<Config>::tryCreate(*this, pageIndex);
            if (!page)
                return EligibilityKind::OutOfMemory;
            m_pages[pageIndex] = page;
        } else {
            // This means that we have a page that we previously allocated and that page just needs to be
            // committed.
            vmAllocatePhysicalPages(page, IsoPageBase::pageSize);
            new (page) IsoPage<Config>(*this, pageIndex);
        }

        m_committed[pageIndex] = true;
        this->m_heap.didCommit(page, IsoPageBase::pageSize);
    } else {
        if (m_empty[pageIndex])
            this->m_heap.isNoLongerFreeable(page, IsoPageBase::pageSize);
    }
    
    RELEASE_BASSERT(page);
    
    // Make the page non-empty and non-eligible.
    m_eligible[pageIndex] = false;
    m_empty[pageIndex] = false;
    return page;
}

template<typename Config, unsigned passedNumPages>
void IsoDirectory<Config, passedNumPages>::didBecome(IsoPage<Config>* page, IsoPageTrigger trigger)
{
    static constexpr bool verbose = false;
    unsigned pageIndex = page->index();
    switch (trigger) {
    case IsoPageTrigger::Eligible:
        if (verbose)
            fprintf(stderr, "%p: %p did become eligible.\n", this, page);
        m_eligible[pageIndex] = true;
        m_firstEligible = std::min(m_firstEligible, pageIndex);
        this->m_heap.didBecomeEligible(this);
        return;
    case IsoPageTrigger::Empty:
        if (verbose)
            fprintf(stderr, "%p: %p did become empty.\n", this, page);
        BASSERT(!!m_committed[pageIndex]);
        this->m_heap.isNowFreeable(page, IsoPageBase::pageSize);
        m_empty[pageIndex] = true;
        PerProcess<Scavenger>::get()->schedule(IsoPageBase::pageSize);
        return;
    }
    BCRASH();
}

template<typename Config, unsigned passedNumPages>
void IsoDirectory<Config, passedNumPages>::didDecommit(unsigned index)
{
    // FIXME: We could do this without grabbing the lock. I just doubt that it matters. This is not going
    // to be a frequently executed path, in the sense that decommitting perf will be dominated by the
    // syscall itself (which has to do many hard things).
    std::lock_guard<Mutex> locker(this->m_heap.lock);
    BASSERT(!!m_committed[index]);
    this->m_heap.isNoLongerFreeable(m_pages[index], IsoPageBase::pageSize);
    m_committed[index] = false;
    this->m_heap.didDecommit(m_pages[index], IsoPageBase::pageSize);
}

template<typename Config, unsigned passedNumPages>
void IsoDirectory<Config, passedNumPages>::scavengePage(size_t index, Vector<DeferredDecommit>& decommits)
{
    // Make sure that this page is now off limits.
    m_empty[index] = false;
    m_eligible[index] = false;
    decommits.push(DeferredDecommit(this, m_pages[index], index));
}

template<typename Config, unsigned passedNumPages>
void IsoDirectory<Config, passedNumPages>::scavenge(Vector<DeferredDecommit>& decommits)
{
    (m_empty & m_committed).forEachSetBit(
        [&] (size_t index) {
            scavengePage(index, decommits);
        });
    m_highWatermark = 0;
}

template<typename Config, unsigned passedNumPages>
void IsoDirectory<Config, passedNumPages>::scavengeToHighWatermark(Vector<DeferredDecommit>& decommits)
{
    (m_empty & m_committed).forEachSetBit(
        [&] (size_t index) {
            if (index > m_highWatermark)
                scavengePage(index, decommits);
        });
    m_highWatermark = 0;
}

template<typename Config, unsigned passedNumPages>
template<typename Func>
void IsoDirectory<Config, passedNumPages>::forEachCommittedPage(const Func& func)
{
    m_committed.forEachSetBit(
        [&] (size_t index) {
            func(*m_pages[index]);
        });
}
    
} // namespace bmalloc

