/*
 * Copyright (C) 2013, 2015 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. AND ITS 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 APPLE INC. OR ITS 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 "config.h"
#include "WeakMapData.h"

#include "ExceptionHelpers.h"
#include "JSCInlines.h"

#include <wtf/MathExtras.h>

namespace JSC {

const ClassInfo WeakMapData::s_info = { "WeakMapData", 0, 0, CREATE_METHOD_TABLE(WeakMapData) };

WeakMapData::WeakMapData(VM& vm)
    : Base(vm, vm.weakMapDataStructure.get())
    , m_deadKeyCleaner(this)
{
}

void WeakMapData::finishCreation(VM& vm)
{
    Base::finishCreation(vm);
}

void WeakMapData::destroy(JSCell* cell)
{
    static_cast<WeakMapData*>(cell)->~WeakMapData();
}

size_t WeakMapData::estimatedSize(JSCell* cell)
{
    WeakMapData* thisObj = jsCast<WeakMapData*>(cell);
    return Base::estimatedSize(cell) + (thisObj->m_map.capacity() * (sizeof(JSObject*) + sizeof(WriteBarrier<Unknown>)));
}

void WeakMapData::visitChildren(JSCell* cell, SlotVisitor& visitor)
{
    Base::visitChildren(cell, visitor);
    WeakMapData* thisObj = jsCast<WeakMapData*>(cell);
    visitor.addUnconditionalFinalizer(&thisObj->m_deadKeyCleaner);
    visitor.addWeakReferenceHarvester(&thisObj->m_deadKeyCleaner);

    // Rough approximation of the external storage needed for the hashtable.
    // This isn't exact, but it is close enough, and proportional to the actual
    // external memory usage.
    visitor.reportExtraMemoryVisited(thisObj->m_map.capacity() * (sizeof(JSObject*) + sizeof(WriteBarrier<Unknown>)));
}

void WeakMapData::set(VM& vm, JSObject* key, JSValue value)
{
    // Here we force the write barrier on the key.
    auto result = m_map.add(WriteBarrier<JSObject>(vm, this, key).get(), WriteBarrier<Unknown>());
    result.iterator->value.set(vm, this, value);
}

JSValue WeakMapData::get(JSObject* key)
{
    auto iter = m_map.find(key);
    if (iter == m_map.end())
        return jsUndefined();
    return iter->value.get();
}

bool WeakMapData::remove(JSObject* key)
{
    auto iter = m_map.find(key);
    if (iter == m_map.end())
        return false;

    m_map.remove(iter);
    return true;
}

bool WeakMapData::contains(JSObject* key)
{
    return m_map.contains(key);
}

void WeakMapData::clear()
{
    m_map.clear();
}

void WeakMapData::DeadKeyCleaner::visitWeakReferences(SlotVisitor& visitor)
{
    m_liveKeyCount = 0;
    for (auto it = m_target->m_map.begin(), end = m_target->m_map.end(); it != end; ++it) {
        if (!Heap::isMarked(it->key))
            continue;
        m_liveKeyCount++;
        visitor.append(&it->value);
    }
    RELEASE_ASSERT(m_liveKeyCount <= m_target->m_map.size());
}

void WeakMapData::DeadKeyCleaner::finalizeUnconditionally()
{
    if (m_liveKeyCount > m_target->m_map.size() / 2) {
        RELEASE_ASSERT(m_liveKeyCount <= m_target->m_map.size());
        int deadCount = m_target->m_map.size() - m_liveKeyCount;
        if (!deadCount)
            return;
        Vector<JSObject*> deadEntries;
        deadEntries.reserveCapacity(deadCount);
        for (auto it = m_target->m_map.begin(), end = m_target->m_map.end(); it != end; ++it) {
            if (Heap::isMarked(it->key))
                continue;
            deadEntries.uncheckedAppend(it->key);
        }
        for (size_t i = 0; i < deadEntries.size(); i++)
            m_target->m_map.remove(deadEntries[i]);
    } else {
        MapType newMap;
        for (auto it = m_target->m_map.begin(), end = m_target->m_map.end(); it != end; ++it) {
            if (!Heap::isMarked(it->key))
                continue;
            newMap.add(it->key, it->value);
        }
        m_target->m_map.swap(newMap);
    }
}

}
