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

#include "config.h"
#include "PolymorphicCallStubRoutine.h"

#if ENABLE(JIT)

#include "CallLinkInfo.h"
#include "CodeBlock.h"
#include "FullCodeOrigin.h"
#include "JSCInlines.h"
#include "LinkBuffer.h"

namespace JSC {

PolymorphicCallNode::~PolymorphicCallNode()
{
    if (isOnList())
        remove();
}

void PolymorphicCallNode::unlink(VM& vm)
{
    if (m_callLinkInfo) {
        if (Options::dumpDisassembly())
            dataLog("Unlinking polymorphic call at ", m_callLinkInfo->callReturnLocation(), ", ", m_callLinkInfo->codeOrigin(), "\n");

        m_callLinkInfo->unlink(vm);
    }

    if (isOnList())
        remove();
}

void PolymorphicCallNode::clearCallLinkInfo()
{
    if (Options::dumpDisassembly())
        dataLog("Clearing call link info for polymorphic call at ", m_callLinkInfo->callReturnLocation(), ", ", m_callLinkInfo->codeOrigin(), "\n");

    m_callLinkInfo = nullptr;
}

void PolymorphicCallCase::dump(PrintStream& out) const
{
    out.print("<variant = ", m_variant, ", codeBlock = ", pointerDump(m_codeBlock), ">");
}

PolymorphicCallStubRoutine::PolymorphicCallStubRoutine(
    const MacroAssemblerCodeRef<JITStubRoutinePtrTag>& codeRef, VM& vm, const JSCell* owner, ExecState* callerFrame,
    CallLinkInfo& info, const Vector<PolymorphicCallCase>& cases,
    UniqueArray<uint32_t>&& fastCounts)
    : GCAwareJITStubRoutine(codeRef, vm)
    , m_fastCounts(WTFMove(fastCounts))
{
    for (PolymorphicCallCase callCase : cases) {
        m_variants.append(WriteBarrier<JSCell>(vm, owner, callCase.variant().rawCalleeCell()));
        if (shouldDumpDisassemblyFor(callerFrame->codeBlock()))
            dataLog("Linking polymorphic call in ", FullCodeOrigin(callerFrame->codeBlock(), callerFrame->codeOrigin()), " to ", callCase.variant(), ", codeBlock = ", pointerDump(callCase.codeBlock()), "\n");
        if (CodeBlock* codeBlock = callCase.codeBlock())
            codeBlock->linkIncomingPolymorphicCall(callerFrame, m_callNodes.add(&info));
    }
    m_variants.shrinkToFit();
    WTF::storeStoreFence();
}

PolymorphicCallStubRoutine::~PolymorphicCallStubRoutine() { }

CallVariantList PolymorphicCallStubRoutine::variants() const
{
    CallVariantList result;
    for (size_t i = 0; i < m_variants.size(); ++i)
        result.append(CallVariant(m_variants[i].get()));
    return result;
}

CallEdgeList PolymorphicCallStubRoutine::edges() const
{
    // We wouldn't have these if this was an FTL stub routine. We shouldn't be asking for profiling
    // from the FTL.
    RELEASE_ASSERT(m_fastCounts);
    
    CallEdgeList result;
    for (size_t i = 0; i < m_variants.size(); ++i)
        result.append(CallEdge(CallVariant(m_variants[i].get()), m_fastCounts[i]));
    return result;
}

void PolymorphicCallStubRoutine::clearCallNodesFor(CallLinkInfo* info)
{
    for (Bag<PolymorphicCallNode>::iterator iter = m_callNodes.begin(); !!iter; ++iter) {
        PolymorphicCallNode& node = **iter;
        // All nodes should point to info, but okay to be a little paranoid.
        if (node.hasCallLinkInfo(info))
            node.clearCallLinkInfo();
    }
}

bool PolymorphicCallStubRoutine::visitWeak(VM&)
{
    for (auto& variant : m_variants) {
        if (!Heap::isMarked(variant.get()))
            return false;
    }
    return true;
}

void PolymorphicCallStubRoutine::markRequiredObjectsInternal(SlotVisitor& visitor)
{
    for (auto& variant : m_variants)
        visitor.append(variant);
}

} // namespace JSC

#endif // ENABLE(JIT)
