/*
 * Copyright (C) 2013-2021 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 "DFGNode.h"

#if ENABLE(DFG_JIT)

#include "DFGGraph.h"
#include "DFGPromotedHeapLocation.h"
#include "DOMJITSignature.h"
#include "JSImmutableButterfly.h"

namespace JSC { namespace DFG {

const char Node::HashSetTemplateInstantiationString[] = "::JSC::DFG::Node*";

DEFINE_ALLOCATOR_WITH_HEAP_IDENTIFIER(DFGNode);

bool MultiPutByOffsetData::writesStructures() const
{
    for (unsigned i = variants.size(); i--;) {
        if (variants[i].writesStructures())
            return true;
    }
    return false;
}

bool MultiPutByOffsetData::reallocatesStorage() const
{
    for (unsigned i = variants.size(); i--;) {
        if (variants[i].reallocatesStorage())
            return true;
    }
    return false;
}

bool MultiDeleteByOffsetData::writesStructures() const
{
    for (unsigned i = variants.size(); i--;) {
        if (variants[i].writesStructures())
            return true;
    }
    return false;
}

bool MultiDeleteByOffsetData::allVariantsStoreEmpty() const
{
    for (unsigned i = variants.size(); i--;) {
        if (!variants[i].newStructure())
            return false;
    }
    return true;
}

void BranchTarget::dump(PrintStream& out) const
{
    if (!block)
        return;
    
    out.print(*block);
    
    if (count == count) // If the count is not NaN, then print it.
        out.print("/w:", count);
}

bool Node::hasVariableAccessData(Graph& graph)
{
    switch (op()) {
    case Phi:
        return graph.m_form != SSA;
    case GetLocal:
    case SetLocal:
    case SetArgumentDefinitely:
    case SetArgumentMaybe:
    case Flush:
    case PhantomLocal:
        return true;
    default:
        return false;
    }
}

void Node::remove(Graph& graph)
{
    switch (op()) {
    case MultiGetByOffset: {
        MultiGetByOffsetData& data = multiGetByOffsetData();
        StructureSet set;
        for (MultiGetByOffsetCase& getCase : data.cases) {
            getCase.set().forEach(
                [&] (RegisteredStructure structure) {
                    set.add(structure.get());
                });
        }
        convertToCheckStructure(graph.addStructureSet(set));
        return;
    }
        
    case MatchStructure: {
        MatchStructureData& data = matchStructureData();
        RegisteredStructureSet set;
        for (MatchStructureVariant& variant : data.variants)
            set.add(variant.structure);
        convertToCheckStructure(graph.addStructureSet(set));
        return;
    }
        
    default:
        if (flags() & NodeHasVarArgs) {
            unsigned targetIndex = 0;
            for (unsigned i = 0; i < numChildren(); ++i) {
                Edge& edge = graph.varArgChild(this, i);
                if (!edge)
                    continue;
                if (edge.willHaveCheck()) {
                    Edge& dst = graph.varArgChild(this, targetIndex++);
                    std::swap(dst, edge);
                    continue;
                }
                edge = Edge();
            }
            setOpAndDefaultFlags(CheckVarargs);
            children.setNumChildren(targetIndex);
        } else {
            children = children.justChecks();
            setOpAndDefaultFlags(Check);
        }
        return;
    }
}

void Node::removeWithoutChecks()
{
    children = AdjacencyList();
    setOpAndDefaultFlags(Check);
}

void Node::replaceWith(Graph& graph, Node* other)
{
    remove(graph);
    setReplacement(other);
}

void Node::replaceWithWithoutChecks(Node* other)
{
    removeWithoutChecks();
    setReplacement(other);
}

void Node::convertToIdentity()
{
    RELEASE_ASSERT(child1());
    RELEASE_ASSERT(!child2());
    NodeFlags result = canonicalResultRepresentation(this->result());
    setOpAndDefaultFlags(Identity);
    setResult(result);
}

void Node::convertToIdentityOn(Node* child)
{
    children.reset();
    clearFlags(NodeHasVarArgs);
    child1() = child->defaultEdge();
    NodeFlags output = canonicalResultRepresentation(this->result());
    NodeFlags input = canonicalResultRepresentation(child->result());
    if (output == input) {
        setOpAndDefaultFlags(Identity);
        setResult(output);
        return;
    }
    switch (output) {
    case NodeResultDouble:
        setOpAndDefaultFlags(DoubleRep);
        switch (input) {
        case NodeResultInt52:
            child1().setUseKind(Int52RepUse);
            return;
        case NodeResultJS:
            child1().setUseKind(NumberUse);
            return;
        default:
            RELEASE_ASSERT_NOT_REACHED();
            return;
        }
    case NodeResultInt52:
        setOpAndDefaultFlags(Int52Rep);
        switch (input) {
        case NodeResultDouble:
            child1().setUseKind(DoubleRepAnyIntUse);
            return;
        case NodeResultJS:
            child1().setUseKind(AnyIntUse);
            return;
        default:
            RELEASE_ASSERT_NOT_REACHED();
            return;
        }
    case NodeResultJS:
        setOpAndDefaultFlags(ValueRep);
        switch (input) {
        case NodeResultDouble:
            child1().setUseKind(DoubleRepUse);
            return;
        case NodeResultInt52:
            child1().setUseKind(Int52RepUse);
            return;
        default:
            RELEASE_ASSERT_NOT_REACHED();
            return;
        }
    default:
        RELEASE_ASSERT_NOT_REACHED();
        return;
    }
}

void Node::convertToLazyJSConstant(Graph& graph, LazyJSValue value)
{
    m_op = LazyJSConstant;
    m_flags &= ~NodeMustGenerate;
    m_opInfo = graph.m_lazyJSValues.add(value);
    children.reset();
}

void Node::convertToNewArrayBuffer(FrozenValue* immutableButterfly)
{
    setOpAndDefaultFlags(NewArrayBuffer);
    NewArrayBufferData data { };
    data.indexingMode = immutableButterfly->cast<JSImmutableButterfly*>()->indexingMode();
    data.vectorLengthHint = immutableButterfly->cast<JSImmutableButterfly*>()->toButterfly()->vectorLength();
    children.reset();
    m_opInfo = immutableButterfly;
    m_opInfo2 = data.asQuadWord;
}

void Node::convertToDirectCall(FrozenValue* executable)
{
    NodeType newOp = LastNodeType;
    switch (op()) {
    case Call:
        newOp = DirectCall;
        break;
    case Construct:
        newOp = DirectConstruct;
        break;
    case TailCallInlinedCaller:
        newOp = DirectTailCallInlinedCaller;
        break;
    case TailCall:
        newOp = DirectTailCall;
        break;
    default:
        RELEASE_ASSERT_NOT_REACHED();
        break;
    }
    
    m_op = newOp;
    m_opInfo = executable;
}

void Node::convertToCallDOM(Graph& graph)
{
    ASSERT(op() == Call);
    ASSERT(signature());

    Edge edges[3];
    // Skip the first one. This is callee.
    RELEASE_ASSERT(numChildren() <= 4);
    for (unsigned i = 1; i < numChildren(); ++i)
        edges[i - 1] = graph.varArgChild(this, i);

    setOpAndDefaultFlags(CallDOM);
    children.setChild1(edges[0]);
    children.setChild2(edges[1]);
    children.setChild3(edges[2]);

    if (!signature()->effect.mustGenerate())
        clearFlags(NodeMustGenerate);
}

void Node::convertToRegExpExecNonGlobalOrStickyWithoutChecks(FrozenValue* regExp)
{
    ASSERT(op() == RegExpExec);
    setOpAndDefaultFlags(RegExpExecNonGlobalOrSticky);
    children.child1() = Edge(children.child1().node(), KnownCellUse);
    children.child2() = Edge(children.child3().node(), KnownStringUse);
    children.child3() = Edge();
    m_opInfo = regExp;
}

void Node::convertToRegExpMatchFastGlobalWithoutChecks(FrozenValue* regExp)
{
    ASSERT(op() == RegExpMatchFast);
    setOpAndDefaultFlags(RegExpMatchFastGlobal);
    children.child1() = Edge(children.child1().node(), KnownCellUse);
    children.child2() = Edge(children.child3().node(), KnownStringUse);
    children.child3() = Edge();
    m_opInfo = regExp;
}

void Node::convertToRegExpTestInline(FrozenValue* globalObject, FrozenValue* regExp)
{
    ASSERT(op() == RegExpTest);
    setOpAndDefaultFlags(RegExpTestInline);
    children.child1() = Edge(children.child1().node(), KnownCellUse);
    children.child2() = Edge(children.child2().node(), RegExpObjectUse);
    // We keep the existing child3.
    m_opInfo = globalObject;
    m_opInfo2 = regExp;
}

String Node::tryGetString(Graph& graph)
{
    if (hasConstant())
        return constant()->tryGetString(graph);
    if (hasLazyJSValue())
        return lazyJSValue().tryGetString(graph);
    return String();
}

PromotedLocationDescriptor Node::promotedLocationDescriptor()
{
    return PromotedLocationDescriptor(static_cast<PromotedLocationKind>(m_opInfo.as<uint32_t>()), m_opInfo2.as<uint32_t>());
}

} } // namespace JSC::DFG

namespace WTF {

using namespace JSC;
using namespace JSC::DFG;

void printInternal(PrintStream& out, SwitchKind kind)
{
    switch (kind) {
    case SwitchImm:
        out.print("SwitchImm");
        return;
    case SwitchChar:
        out.print("SwitchChar");
        return;
    case SwitchString:
        out.print("SwitchString");
        return;
    case SwitchCell:
        out.print("SwitchCell");
        return;
    }
    RELEASE_ASSERT_NOT_REACHED();
}

void printInternal(PrintStream& out, Node* node)
{
    if (!node) {
        out.print("-");
        return;
    }
    out.print("D@", node->index());
    if (node->hasDoubleResult())
        out.print("<Double>");
    else if (node->hasInt52Result())
        out.print("<Int52>");
}

} // namespace WTF

#endif // ENABLE(DFG_JIT)

