/*
 * Copyright (C) 2015-2017 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 "B3FrequentedBlock.h"
#include "B3Opcode.h"
#include "B3Origin.h"
#include "B3SuccessorCollection.h"
#include "B3Type.h"
#include <wtf/Vector.h>

namespace JSC { namespace B3 {

class BlockInsertionSet;
class InsertionSet;
class Procedure;
class Value;
template<typename> class GenericBlockInsertionSet;

class BasicBlock {
    WTF_MAKE_NONCOPYABLE(BasicBlock);
    WTF_MAKE_FAST_ALLOCATED;
public:
    typedef Vector<Value*> ValueList;
    typedef Vector<BasicBlock*, 2> PredecessorList;
    typedef Vector<FrequentedBlock, 2> SuccessorList;

    static constexpr unsigned uninsertedIndex = UINT_MAX;
    static const char* const dumpPrefix;

    ~BasicBlock();

    unsigned index() const { return m_index; }
    bool isInserted() const { return m_index != uninsertedIndex; }

    ValueList::iterator begin() { return m_values.begin(); }
    ValueList::iterator end() { return m_values.end(); }
    ValueList::const_iterator begin() const { return m_values.begin(); }
    ValueList::const_iterator end() const { return m_values.end(); }

    size_t size() const { return m_values.size(); }
    Value* at(size_t index) const { return m_values[index]; }
    Value*& at(size_t index) { return m_values[index]; }
    
    Value* get(size_t index) const
    {
        if (index >= size())
            return nullptr;
        return at(index);
    }

    Value* last() const { return m_values.last(); }
    Value*& last() { return m_values.last(); }

    const ValueList& values() const { return m_values; }
    ValueList& values() { return m_values; }

    JS_EXPORT_PRIVATE void append(Value*);
    JS_EXPORT_PRIVATE void appendNonTerminal(Value*);
    JS_EXPORT_PRIVATE void replaceLast(Procedure&, Value*);

    template<typename ValueType, typename... Arguments>
    ValueType* appendNew(Procedure&, Arguments...);

    JS_EXPORT_PRIVATE Value* appendIntConstant(Procedure&, Origin, Type, int64_t value);
    Value* appendIntConstant(Procedure&, Value* likeValue, int64_t value);
    Value* appendBoolConstant(Procedure&, Origin, bool);

    void removeLast(Procedure&);
    
    template<typename ValueType, typename... Arguments>
    ValueType* replaceLastWithNew(Procedure&, Arguments...);

    unsigned numSuccessors() const { return m_successors.size(); }
    const FrequentedBlock& successor(unsigned index) const { return m_successors[index]; }
    FrequentedBlock& successor(unsigned index) { return m_successors[index]; }
    const SuccessorList& successors() const { return m_successors; }
    SuccessorList& successors() { return m_successors; }
    
    void clearSuccessors();
    JS_EXPORT_PRIVATE void appendSuccessor(FrequentedBlock);
    JS_EXPORT_PRIVATE void setSuccessors(FrequentedBlock);
    JS_EXPORT_PRIVATE void setSuccessors(FrequentedBlock, FrequentedBlock);

    BasicBlock* successorBlock(unsigned index) const { return successor(index).block(); }
    BasicBlock*& successorBlock(unsigned index) { return successor(index).block(); }
    SuccessorCollection<BasicBlock, SuccessorList> successorBlocks()
    {
        return SuccessorCollection<BasicBlock, SuccessorList>(successors());
    }
    SuccessorCollection<const BasicBlock, const SuccessorList> successorBlocks() const
    {
        return SuccessorCollection<const BasicBlock, const SuccessorList>(successors());
    }

    bool replaceSuccessor(BasicBlock* from, BasicBlock* to);
    
    // This is only valid for Jump and Branch.
    const FrequentedBlock& taken() const;
    FrequentedBlock& taken();
    // This is only valid for Branch.
    const FrequentedBlock& notTaken() const;
    FrequentedBlock& notTaken();
    // This is only valid for Branch and Switch.
    const FrequentedBlock& fallThrough() const;
    FrequentedBlock& fallThrough();

    unsigned numPredecessors() const { return m_predecessors.size(); }
    BasicBlock* predecessor(unsigned index) const { return m_predecessors[index]; }
    BasicBlock*& predecessor(unsigned index) { return m_predecessors[index]; }
    const PredecessorList& predecessors() const { return m_predecessors; }
    PredecessorList& predecessors() { return m_predecessors; }
    bool containsPredecessor(BasicBlock* block) { return m_predecessors.contains(block); }

    bool addPredecessor(BasicBlock*);
    bool removePredecessor(BasicBlock*);
    bool replacePredecessor(BasicBlock* from, BasicBlock* to);

    // Update predecessors starting with the successors of this block.
    void updatePredecessorsAfter();

    void setFrequency(double frequency) { m_frequency = frequency; }
    double frequency() const { return m_frequency; }

    void dump(PrintStream&) const;
    void deepDump(const Procedure&, PrintStream&) const;

    // These are deprecated method for compatibility with the old ControlValue class. Don't use them
    // in new code.
    // FIXME: https://bugs.webkit.org/show_bug.cgi?id=159440
    
    // Use this for Oops.
    JS_EXPORT_PRIVATE Value* appendNewControlValue(Procedure&, Opcode, Origin);
    // Use this for Return.
    JS_EXPORT_PRIVATE Value* appendNewControlValue(Procedure&, Opcode, Origin, Value*);
    // Use this for Jump.
    JS_EXPORT_PRIVATE Value* appendNewControlValue(Procedure&, Opcode, Origin, const FrequentedBlock&);
    // Use this for Branch.
    JS_EXPORT_PRIVATE Value* appendNewControlValue(Procedure&, Opcode, Origin, Value*, const FrequentedBlock&, const FrequentedBlock&);
    
private:
    friend class BlockInsertionSet;
    friend class InsertionSet;
    friend class Procedure;
    template<typename> friend class GenericBlockInsertionSet;
    
    // Instantiate via Procedure.
    BasicBlock(unsigned index, double frequency);

    unsigned m_index;
    ValueList m_values;
    PredecessorList m_predecessors;
    SuccessorList m_successors;
    double m_frequency;
};

class DeepBasicBlockDump {
public:
    DeepBasicBlockDump(const Procedure& proc, const BasicBlock* block)
        : m_proc(proc)
        , m_block(block)
    {
    }

    void dump(PrintStream& out) const
    {
        if (m_block)
            m_block->deepDump(m_proc, out);
        else
            out.print("<null>");
    }

private:
    const Procedure& m_proc;
    const BasicBlock* m_block;
};

inline DeepBasicBlockDump deepDump(const Procedure& proc, const BasicBlock* block)
{
    return DeepBasicBlockDump(proc, block);
}

} } // namespace JSC::B3

#endif // ENABLE(B3_JIT)
