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

#pragma once

#if ENABLE(B3_JIT)

#include "AirKind.h"
#include "B3StackmapSpecial.h"
#include <wtf/HashMap.h>

namespace JSC { namespace B3 {

namespace Air {
struct Inst;
}

// We want to lower Check instructions to a branch, but then we want to route that branch to our
// out-of-line code instead of doing anything else. For this reason, a CheckSpecial will remember
// which branch opcode we have selected along with the number of args in the overload we want. It
// will create an Inst with that opcode plus the appropriate args from the owning Inst whenever you
// call any of the callbacks.
//
// Note that for CheckAdd, CheckSub, and CheckMul we expect that the B3 arguments are the reverse
// of the Air arguments (Add(a, b) => Add32 b, a). Except:
// - CheckSub(0, x), which turns into BranchNeg32 x.
// - CheckMul(a, b), which turns into Mul32 b, a but we pass Any for a's ValueRep.

class CheckSpecial : public StackmapSpecial {
public:
    // Support for hash consing these things.
    class Key {
    public:
        Key()
            : m_stackmapRole(SameAsRep)
            , m_numArgs(0)
        {
        }
        
        Key(Air::Kind kind, unsigned numArgs, RoleMode stackmapRole = SameAsRep)
            : m_kind(kind)
            , m_stackmapRole(stackmapRole)
            , m_numArgs(numArgs)
        {
        }

        explicit Key(const Air::Inst&);

        bool operator==(const Key& other) const
        {
            return m_kind == other.m_kind
                && m_numArgs == other.m_numArgs
                && m_stackmapRole == other.m_stackmapRole;
        }

        bool operator!=(const Key& other) const
        {
            return !(*this == other);
        }

        explicit operator bool() const { return *this != Key(); }

        Air::Kind kind() const { return m_kind; }
        unsigned numArgs() const { return m_numArgs; }
        RoleMode stackmapRole() const { return m_stackmapRole; }

        void dump(PrintStream& out) const;

        Key(WTF::HashTableDeletedValueType)
            : m_stackmapRole(SameAsRep)
            , m_numArgs(1)
        {
        }

        bool isHashTableDeletedValue() const
        {
            return *this == Key(WTF::HashTableDeletedValue);
        }

        unsigned hash() const
        {
            // Seriously, we don't need to be smart here. It just doesn't matter.
            return m_kind.hash() + m_numArgs + m_stackmapRole;
        }
        
    private:
        Air::Kind m_kind;
        RoleMode m_stackmapRole;
        unsigned m_numArgs;
    };
    
    CheckSpecial(Air::Kind, unsigned numArgs, RoleMode stackmapRole = SameAsRep);
    CheckSpecial(const Key&);
    ~CheckSpecial();

protected:
    // Constructs and returns the Inst representing the branch that this will use.
    Air::Inst hiddenBranch(const Air::Inst&) const;

    void forEachArg(Air::Inst&, const ScopedLambda<Air::Inst::EachArgCallback>&) final;
    bool isValid(Air::Inst&) final;
    bool admitsStack(Air::Inst&, unsigned argIndex) final;
    bool admitsExtendedOffsetAddr(Air::Inst&, unsigned) final;
    Optional<unsigned> shouldTryAliasingDef(Air::Inst&) final;

    // NOTE: the generate method will generate the hidden branch and then register a LatePath that
    // generates the stackmap. Super crazy dude!

    MacroAssembler::Jump generate(Air::Inst&, CCallHelpers&, Air::GenerationContext&) final;

    void dumpImpl(PrintStream&) const final;
    void deepDumpImpl(PrintStream&) const final;

private:
    Air::Kind m_checkKind;
    RoleMode m_stackmapRole;
    unsigned m_numCheckArgs;
};

struct CheckSpecialKeyHash {
    static unsigned hash(const CheckSpecial::Key& key) { return key.hash(); }
    static bool equal(const CheckSpecial::Key& a, const CheckSpecial::Key& b) { return a == b; }
    static constexpr bool safeToCompareToEmptyOrDeleted = true;
};

} } // namespace JSC::B3

namespace WTF {

template<typename T> struct DefaultHash;
template<> struct DefaultHash<JSC::B3::CheckSpecial::Key> {
    typedef JSC::B3::CheckSpecialKeyHash Hash;
};

template<typename T> struct HashTraits;
template<> struct HashTraits<JSC::B3::CheckSpecial::Key> : SimpleClassHashTraits<JSC::B3::CheckSpecial::Key> {
    // I don't want to think about this very hard, it's not worth it. I'm a be conservative.
    static constexpr bool emptyValueIsZero = false;
};

} // namespace WTF

#endif // ENABLE(B3_JIT)
