/*
 * Copyright (C) 2014 Google 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:
 *
 *     * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *     * 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.
 *     * Neither the name of Google Inc. nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "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 THE COPYRIGHT
 * OWNER 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.
 */

#include "sky/engine/platform/PurgeableVector.h"

#include "sky/engine/public/platform/Platform.h"
#include "sky/engine/public/platform/WebDiscardableMemory.h"
#include "sky/engine/wtf/Assertions.h"
#include "sky/engine/wtf/OwnPtr.h"
#include "sky/engine/wtf/PassOwnPtr.h"

#include <cstring>

namespace blink {

// WebDiscardableMemory allocations are expensive and page-grained. We only use
// them when there's a reasonable amount of memory to be saved by the OS
// discarding the memory.
static const size_t minimumDiscardableAllocationSize = 4 * 4096;

PurgeableVector::PurgeableVector(PurgeableOption purgeable)
    : m_discardableCapacity(0)
    , m_discardableSize(0)
    , m_isPurgeable(purgeable == Purgeable)
    , m_locksCount(1) // The buffer is locked at creation.
{
}

PurgeableVector::~PurgeableVector()
{
}

void PurgeableVector::reserveCapacity(size_t capacity)
{
    ASSERT(isLocked());

    if (m_isPurgeable) {
        if (reservePurgeableCapacity(capacity, UseExactCapacity))
            return;
        // Fallback to non-purgeable buffer allocation in case discardable memory allocation failed.
    }

    if (!m_vector.capacity()) {
        // Using reserveInitialCapacity() on the underlying vector ensures that the vector uses the
        // exact specified capacity to avoid consuming too much memory for small resources.
        m_vector.reserveInitialCapacity(capacity);
    } else {
        m_vector.reserveCapacity(capacity);
    }

    moveDataFromDiscardableToVector();
}

void PurgeableVector::moveDataFromDiscardableToVector()
{
    if (m_discardable) {
        m_vector.append(static_cast<const char*>(m_discardable->data()), m_discardableSize);
        clearDiscardable();
    }
}

void PurgeableVector::clearDiscardable()
{
    m_discardable.clear();
    m_discardableCapacity = 0;
    m_discardableSize = 0;
}

void PurgeableVector::append(const char* data, size_t length)
{
    ASSERT(isLocked());

    if (!m_isPurgeable) {
        m_vector.append(data, length);
        return;
    }

    const size_t currentSize = m_discardable ? m_discardableSize : m_vector.size();
    const size_t newBufferSize = currentSize + length;

    if (!reservePurgeableCapacity(newBufferSize, UseExponentialGrowth)) {
        moveDataFromDiscardableToVector();
        m_vector.append(data, length);
        return;
    }

    ASSERT(m_discardableSize + length <= m_discardableCapacity);
    memcpy(static_cast<char*>(m_discardable->data()) + m_discardableSize, data, length);
    m_discardableSize += length;
}

void PurgeableVector::grow(size_t newSize)
{
    ASSERT(newSize >= size());

    if (m_isPurgeable) {
        if (reservePurgeableCapacity(newSize, UseExponentialGrowth)) {
            m_discardableSize = newSize;
            return;
        }
        moveDataFromDiscardableToVector();
    }

    m_vector.resize(newSize);
}

void PurgeableVector::clear()
{
    clearDiscardable();
    m_vector.clear();
}

char* PurgeableVector::data()
{
    ASSERT(isLocked());
    return m_discardable ? static_cast<char*>(m_discardable->data()) : m_vector.data();
}

size_t PurgeableVector::size() const
{
    return m_discardable ? m_discardableSize : m_vector.size();
}

void PurgeableVector::adopt(Vector<char>& other)
{
    if (size() > 0)
        clear();

    if (!m_isPurgeable) {
        m_vector.swap(other);
        return;
    }

    if (other.isEmpty())
        return;

    append(other.data(), other.size());
    other.clear();
}

bool PurgeableVector::lock()
{
    ++m_locksCount;
    if (m_locksCount > 1)
        return true;

    ASSERT(m_locksCount == 1);
    if (!m_discardable)
        return true;

    return m_discardable->lock();
}

void PurgeableVector::unlock()
{
    ASSERT(isLocked());
    --m_locksCount;
    if (m_locksCount > 0)
        return;

    if (!m_vector.isEmpty()) {
        ASSERT(!m_discardable);
        m_isPurgeable = true;
        if (!reservePurgeableCapacity(m_vector.size(), UseExactCapacity))
            return;
    }

    if (m_discardable)
        m_discardable->unlock();
}

bool PurgeableVector::isLocked() const
{
    ASSERT(m_locksCount >= 0);
    return m_locksCount > 0;
}

bool PurgeableVector::reservePurgeableCapacity(size_t capacity, PurgeableAllocationStrategy allocationStrategy)
{
    ASSERT(m_isPurgeable);

    if (m_discardable && m_discardableCapacity >= capacity) {
        ASSERT(!m_vector.capacity());
        return true;
    }

    if (capacity < minimumDiscardableAllocationSize)
        return false;

    if (allocationStrategy == UseExponentialGrowth)
        capacity = adjustPurgeableCapacity(capacity);

    OwnPtr<blink::WebDiscardableMemory> discardable = adoptPtr(
        blink::Platform::current()->allocateAndLockDiscardableMemory(capacity));
    if (!discardable) {
        // Discardable memory is not supported.
        m_isPurgeable = false;
        return false;
    }

    m_discardableCapacity = capacity;
    // Copy the data that was either in the previous purgeable buffer or in the vector to the new
    // purgeable buffer.
    if (m_discardable) {
        memcpy(discardable->data(), m_discardable->data(), m_discardableSize);
    } else {
        memcpy(discardable->data(), m_vector.data(), m_vector.size());
        m_discardableSize = m_vector.size();
        m_vector.clear();
    }

    m_discardable.swap(discardable);
    ASSERT(!m_vector.capacity());
    return true;
}

size_t PurgeableVector::adjustPurgeableCapacity(size_t capacity) const
{
    ASSERT(capacity >= minimumDiscardableAllocationSize);

    const float growthFactor = 1.5;
    size_t newCapacity = std::max(capacity, static_cast<size_t>(m_discardableCapacity * growthFactor));

    // Discardable memory has page-granularity so align to the next page here to minimize
    // fragmentation.
    // Since the page size is only used below to minimize fragmentation it's still safe to use it
    // even if it gets out of sync (e.g. due to the use of huge pages).
    const size_t kPageSize = 4096;
    newCapacity = (newCapacity + kPageSize - 1) & ~(kPageSize - 1);

    return std::max(capacity, newCapacity); // Overflow check.
}

} // namespace blink
