/*
 * Copyright (C) 2008-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.
 * 3.  Neither the name of Apple Inc. ("Apple") nor the names of
 *     its contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY APPLE 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 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 <wtf/Assertions.h>
#include <wtf/Vector.h>
#include <limits.h>

namespace JSC {
    template<typename Traits>
    class BytecodeGeneratorBase;
    struct JSGeneratorTraits;

    template<typename Traits>
    class GenericLabel;

    template<typename Traits>
    class GenericBoundLabel {
        using BytecodeGenerator = BytecodeGeneratorBase<Traits>;
        using Label = GenericLabel<Traits>;

    public:
        GenericBoundLabel()
            : m_type(Offset)
            , m_generator(nullptr)
            , m_target(0)
        { }

        explicit GenericBoundLabel(int target)
            : m_type(Offset)
            , m_generator(nullptr)
            , m_target(target)
        { }

        GenericBoundLabel(BytecodeGenerator* generator, Label* label)
            : m_type(GeneratorForward)
            , m_generator(generator)
            , m_label(label)
        { }

        GenericBoundLabel(BytecodeGenerator* generator, int offset)
            : m_type(GeneratorBackward)
            , m_generator(generator)
            , m_target(offset)
        { }

        int target()
        {
            switch (m_type) {
            case Offset:
                return m_target;
            case GeneratorBackward:
                return m_target - m_generator->m_writer.position();
            case GeneratorForward:
                return 0;
            default:
                RELEASE_ASSERT_NOT_REACHED();
            }
        }

        int saveTarget()
        {
            if (m_type == GeneratorForward) {
                m_savedTarget = m_generator->m_writer.position();
                return 0;
            }

            m_savedTarget = target();
            return m_savedTarget;
        }

        int commitTarget()
        {
            if (m_type == GeneratorForward) {
                m_label->m_unresolvedJumps.append(m_savedTarget);
                return 0;
            }

            return m_savedTarget;
        }

        operator int() { return target(); }

    private:
        enum Type : uint8_t {
            Offset,
            GeneratorForward,
            GeneratorBackward,
        };

        Type m_type;
        int m_savedTarget { 0 };
        BytecodeGenerator* m_generator;
        union {
            Label* m_label;
            int m_target;
        };
    };

    template<typename Traits>
    class GenericLabel {
        WTF_MAKE_NONCOPYABLE(GenericLabel);
        using BytecodeGenerator = BytecodeGeneratorBase<Traits>;
        using BoundLabel = GenericBoundLabel<Traits>;
        using JumpVector = Vector<int, 8>;

    public:
        GenericLabel() = default;

        void setLocation(BytecodeGenerator&, unsigned location);

        BoundLabel bind(BytecodeGenerator* generator)
        {
            m_bound = true;
            if (!isForward())
                return BoundLabel(generator, m_location);
            return BoundLabel(generator, this);
        }

        BoundLabel bind(unsigned offset)
        {
            m_bound = true;
            if (!isForward())
                return BoundLabel(m_location - offset);
            m_unresolvedJumps.append(offset);
            return BoundLabel();
        }

        BoundLabel bind()
        {
            ASSERT(!isForward());
            return bind(0u);
        }

        void ref() { ++m_refCount; }
        void deref()
        {
            --m_refCount;
            ASSERT(m_refCount >= 0);
        }
        int refCount() const { return m_refCount; }
        bool hasOneRef() const { return m_refCount == 1; }

        bool isForward() const { return m_location == invalidLocation; }
        
        bool isBound() const { return m_bound; }

        unsigned location() const
        {
            ASSERT(!isForward());
            m_bound = true;
            return m_location;
        };

        const JumpVector& unresolvedJumps() const { return  m_unresolvedJumps; }

    private:
        friend BoundLabel;

        static constexpr unsigned invalidLocation = UINT_MAX;

        int m_refCount { 0 };
        unsigned m_location { invalidLocation };
        mutable bool m_bound { false };
        mutable JumpVector m_unresolvedJumps;
    };

    using Label = GenericLabel<JSGeneratorTraits>;
    using BoundLabel = GenericBoundLabel<JSGeneratorTraits>;

    namespace Wasm {
    struct GeneratorTraits;
    using Label = GenericLabel<Wasm::GeneratorTraits>;
    }

    // This cannot be declared in the Wasm namespace as it conflicts with the
    // ruby Wasm namespace when referencing it from BytecodeList.rb
    using WasmBoundLabel = GenericBoundLabel<Wasm::GeneratorTraits>;

} // namespace JSC
