/*
 * Copyright (C) 2011-2019 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.
 */

#pragma once

#include "Handle.h"
#include "HandleBlock.h"
#include "HeapCell.h"
#include <wtf/DoublyLinkedList.h>
#include <wtf/HashCountedSet.h>
#include <wtf/SentinelLinkedList.h>
#include <wtf/SinglyLinkedList.h>

namespace JSC {

class HandleSet;
class VM;
class JSValue;
class SlotVisitor;

class HandleNode {
public:
    HandleNode(WTF::SentinelTag);
    HandleNode();
    
    HandleSlot slot();
    HandleSet* handleSet();

    void setPrev(HandleNode*);
    HandleNode* prev();

    void setNext(HandleNode*);
    HandleNode* next();

private:
    JSValue m_value;
    HandleNode* m_prev;
    HandleNode* m_next;
};

class HandleSet {
    friend class HandleBlock;
public:
    static HandleSet* heapFor(HandleSlot);

    HandleSet(VM&);
    ~HandleSet();

    VM& vm();

    HandleSlot allocate();
    void deallocate(HandleSlot);

    void visitStrongHandles(SlotVisitor&);

    JS_EXPORT_PRIVATE void writeBarrier(HandleSlot, const JSValue&);

    unsigned protectedGlobalObjectCount();

    template<typename Functor> void forEachStrongHandle(const Functor&, const HashCountedSet<JSCell*>& skipSet);

private:
    typedef HandleNode Node;
    static HandleSlot toHandle(Node*);
    static Node* toNode(HandleSlot);

    JS_EXPORT_PRIVATE void grow();
    
#if ENABLE(GC_VALIDATION) || ASSERT_ENABLED
    bool isLiveNode(Node*);
#endif

    VM& m_vm;
    DoublyLinkedList<HandleBlock> m_blockList;

    SentinelLinkedList<Node> m_strongList;
    SentinelLinkedList<Node> m_immediateList;
    SinglyLinkedList<Node> m_freeList;
};

inline HandleSet* HandleSet::heapFor(HandleSlot handle)
{
    return toNode(handle)->handleSet();
}

inline VM& HandleSet::vm()
{
    return m_vm;
}

inline HandleSlot HandleSet::toHandle(HandleSet::Node* node)
{
    return reinterpret_cast<HandleSlot>(node);
}

inline HandleSet::Node* HandleSet::toNode(HandleSlot handle)
{
    return reinterpret_cast<HandleSet::Node*>(handle);
}

inline HandleSlot HandleSet::allocate()
{
    if (m_freeList.isEmpty())
        grow();

    HandleSet::Node* node = m_freeList.pop();
    new (NotNull, node) HandleSet::Node();
    m_immediateList.push(node);
    return toHandle(node);
}

inline void HandleSet::deallocate(HandleSlot handle)
{
    HandleSet::Node* node = toNode(handle);
    SentinelLinkedList<HandleSet::Node>::remove(node);
    m_freeList.push(node);
}

inline HandleNode::HandleNode()
    : m_prev(0)
    , m_next(0)
{
}

inline HandleNode::HandleNode(WTF::SentinelTag)
    : m_prev(0)
    , m_next(0)
{
}

inline HandleSlot HandleNode::slot()
{
    return &m_value;
}

inline HandleSet* HandleNode::handleSet()
{
    return HandleBlock::blockFor(this)->handleSet();
}

inline void HandleNode::setPrev(HandleNode* prev)
{
    m_prev = prev;
}

inline HandleNode* HandleNode::prev()
{
    return m_prev;
}

inline void HandleNode::setNext(HandleNode* next)
{
    m_next = next;
}

inline HandleNode* HandleNode::next()
{
    return m_next;
}

template<typename Functor> void HandleSet::forEachStrongHandle(const Functor& functor, const HashCountedSet<JSCell*>& skipSet)
{
    HandleSet::Node* end = m_strongList.end();
    for (HandleSet::Node* node = m_strongList.begin(); node != end; node = node->next()) {
        JSValue value = *node->slot();
        if (!value || !value.isCell())
            continue;
        if (skipSet.contains(value.asCell()))
            continue;
        functor(value.asCell());
    }
}

} // namespace JSC
