<commit_before>#ifndef ENTT_ENTITY_RUNTIME_VIEW_HPP
#define ENTT_ENTITY_RUNTIME_VIEW_HPP

#include <algorithm>
#include <iterator>
#include <type_traits>
#include <utility>
#include <vector>
#include "../config/config.h"
#include "entity.hpp"
#include "fwd.hpp"
#include "sparse_set.hpp"

namespace entt {

/**
 * @cond TURN_OFF_DOXYGEN
 * Internal details not to be documented.
 */

namespace internal {

template<typename Type>
class runtime_view_iterator final {
    [[nodiscard]] bool valid() const {
        return std::all_of(pools->begin(), pools->end(), [entt = *it](const auto *curr) { return curr->contains(entt); })
               && std::none_of(filter->cbegin(), filter->cend(), [entt = *it](const auto *curr) { return curr && curr->contains(entt); });
    }

public:
    using iterator_type = typename Type::iterator;
    using difference_type = typename iterator_type::difference_type;
    using value_type = typename iterator_type::value_type;
    using pointer = typename iterator_type::pointer;
    using reference = typename iterator_type::reference;
    using iterator_category = std::bidirectional_iterator_tag;

    runtime_view_iterator() ENTT_NOEXCEPT = default;

    runtime_view_iterator(const std::vector<const Type *> &cpools, const std::vector<const Type *> &ignore, iterator_type curr) ENTT_NOEXCEPT
        : pools{&cpools},
          filter{&ignore},
          it{curr} {
        if(it != (*pools)[0]->end() && !valid()) {
            ++(*this);
        }
    }

    runtime_view_iterator &operator++() {
        while(++it != (*pools)[0]->end() && !valid()) {}
        return *this;
    }

    runtime_view_iterator operator++(int) {
        runtime_view_iterator orig = *this;
        return ++(*this), orig;
    }

    runtime_view_iterator &operator--() ENTT_NOEXCEPT {
        while(--it != (*pools)[0]->begin() && !valid()) {}
        return *this;
    }

    runtime_view_iterator operator--(int) ENTT_NOEXCEPT {
        runtime_view_iterator orig = *this;
        return operator--(), orig;
    }

    [[nodiscard]] pointer operator->() const {
        return it.operator->();
    }

    [[nodiscard]] reference operator*() const {
        return *operator->();
    }

    [[nodiscard]] bool operator==(const runtime_view_iterator &other) const ENTT_NOEXCEPT {
        return it == other.it;
    }

    [[nodiscard]] bool operator!=(const runtime_view_iterator &other) const ENTT_NOEXCEPT {
        return !(*this == other);
    }

private:
    const std::vector<const Type *> *pools;
    const std::vector<const Type *> *filter;
    iterator_type it;
};

} // namespace internal

/**
 * Internal details not to be documented.
 * @endcond
 */

/**
 * @brief Runtime view.
 *
 * Runtime views iterate over those entities that have at least all the given
 * components in their bags. During initialization, a runtime view looks at the
 * number of entities available for each component and picks up a reference to
 * the smallest set of candidate entities in order to get a performance boost
 * when iterate.

 * Order of elements during iterations are highly dependent on the order of the
 * underlying data structures. See sparse_set and its specializations for more
 * details.
 *
 * @b Important
 *
 * Iterators aren't invalidated if:
 *
 * * New instances of the given components are created and assigned to entities.
 * * The entity currently pointed is modified (as an example, if one of the
 *   given components is removed from the entity to which the iterator points).
 * * The entity currently pointed is destroyed.
 *
 * In all the other cases, modifying the pools of the given components in any
 * way invalidates all the iterators and using them results in undefined
 * behavior.
 *
 * @note
 * Views share references to the underlying data structures of the registry that
 * generated them. Therefore any change to the entities and to the components
 * made by means of the registry are immediately reflected by the views, unless
 * a pool was missing when the view was built (in this case, the view won't
 * have a valid reference and won't be updated accordingly).
 *
 * @warning
 * Lifetime of a view must not overcome that of the registry that generated it.
 * In any other case, attempting to use a view results in undefined behavior.
 *
 * @tparam Entity A valid entity type (see entt_traits for more details).
 */
template<typename Entity>
class basic_runtime_view final {
    using basic_common_type = basic_sparse_set<Entity>;

    [[nodiscard]] bool valid() const {
        return !pools.empty() && pools.front();
    }

public:
    /*! @brief Underlying entity identifier. */
    using entity_type = Entity;
    /*! @brief Unsigned integer type. */
    using size_type = std::size_t;
    /*! @brief Bidirectional iterator type. */
    using iterator = internal::runtime_view_iterator<basic_common_type>;

    /*! @brief Default constructor to use to create empty, invalid views. */
    basic_runtime_view() ENTT_NOEXCEPT
        : pools{},
          filter{} {}

    /**
     * @brief Constructs a runtime view from a set of storage classes.
     * @param cpools The storage for the types to iterate.
     * @param epools The storage for the types used to filter the view.
     */
    basic_runtime_view(std::vector<const basic_common_type *> cpools, std::vector<const basic_common_type *> epools) ENTT_NOEXCEPT
        : pools{std::move(cpools)},
          filter{std::move(epools)} {
        auto candidate = std::min_element(pools.begin(), pools.end(), [](const auto *lhs, const auto *rhs) {
            return (!lhs && rhs) || (lhs && rhs && lhs->size() < rhs->size());
        });

        // brings the best candidate (if any) on front of the vector
        std::rotate(pools.begin(), candidate, pools.end());
    }

    /**
     * @brief Estimates the number of entities iterated by the view.
     * @return Estimated number of entities iterated by the view.
     */
    [[nodiscard]] size_type size_hint() const {
        return valid() ? pools.front()->size() : size_type{};
    }

    /**
     * @brief Returns an iterator to the first entity that has the given
     * components.
     *
     * The returned iterator points to the first entity that has the given
     * components. If the view is empty, the returned iterator will be equal to
     * `end()`.
     *
     * @return An iterator to the first entity that has the given components.
     */
    [[nodiscard]] iterator begin() const {
        return valid() ? iterator{pools, filter, pools[0]->begin()} : iterator{};
    }

    /**
     * @brief Returns an iterator that is past the last entity that has the
     * given components.
     *
     * The returned iterator points to the entity following the last entity that
     * has the given components. Attempting to dereference the returned iterator
     * results in undefined behavior.
     *
     * @return An iterator to the entity following the last entity that has the
     * given components.
     */
    [[nodiscard]] iterator end() const {
        return valid() ? iterator{pools, filter, pools[0]->end()} : iterator{};
    }

    /**
     * @brief Checks if a view contains an entity.
     * @param entt A valid identifier.
     * @return True if the view contains the given entity, false otherwise.
     */
    [[nodiscard]] bool contains(const entity_type entt) const {
        return valid() && std::all_of(pools.cbegin(), pools.cend(), [entt](const auto *curr) { return curr->contains(entt); })
               && std::none_of(filter.cbegin(), filter.cend(), [entt](const auto *curr) { return curr && curr->contains(entt); });
    }

    /**
     * @brief Iterates entities and applies the given function object to them.
     *
     * The function object is invoked for each entity. It is provided only with
     * the entity itself. To get the components, users can use the registry with
     * which the view was built.

     * The signature of the function should be equivalent to the following:
     *
     * @code{.cpp}
     * void(const entity_type);
     * @endcode
     *
     * @tparam Func Type of the function object to invoke.
     * @param func A valid function object.
     */
    template<typename Func>
    void each(Func func) const {
        for(const auto entity: *this) {
            func(entity);
        }
    }

private:
    std::vector<const basic_common_type *> pools;
    std::vector<const basic_common_type *> filter;
};

} // namespace entt

#endif
<commit_msg>runtime_view: slightly optimized iterators<commit_after>#ifndef ENTT_ENTITY_RUNTIME_VIEW_HPP
#define ENTT_ENTITY_RUNTIME_VIEW_HPP

#include <algorithm>
#include <iterator>
#include <type_traits>
#include <utility>
#include <vector>
#include "../config/config.h"
#include "entity.hpp"
#include "fwd.hpp"
#include "sparse_set.hpp"

namespace entt {

/**
 * @cond TURN_OFF_DOXYGEN
 * Internal details not to be documented.
 */

namespace internal {

template<typename Type>
class runtime_view_iterator final {
    [[nodiscard]] bool valid() const {
        return (!tombstone_check || *it != tombstone)
               && std::all_of(++pools->begin(), pools->end(), [entt = *it](const auto *curr) { return curr->contains(entt); })
               && std::none_of(filter->cbegin(), filter->cend(), [entt = *it](const auto *curr) { return curr && curr->contains(entt); });
    }

public:
    using iterator_type = typename Type::iterator;
    using difference_type = typename iterator_type::difference_type;
    using value_type = typename iterator_type::value_type;
    using pointer = typename iterator_type::pointer;
    using reference = typename iterator_type::reference;
    using iterator_category = std::bidirectional_iterator_tag;

    runtime_view_iterator() ENTT_NOEXCEPT = default;

    runtime_view_iterator(const std::vector<const Type *> &cpools, const std::vector<const Type *> &ignore, iterator_type curr) ENTT_NOEXCEPT
        : pools{&cpools},
          filter{&ignore},
          it{curr},
          tombstone_check{pools->size() == 1u && (*pools)[0u]->policy() == deletion_policy::in_place} {
        if(it != (*pools)[0]->end() && !valid()) {
            ++(*this);
        }
    }

    runtime_view_iterator &operator++() {
        while(++it != (*pools)[0]->end() && !valid()) {}
        return *this;
    }

    runtime_view_iterator operator++(int) {
        runtime_view_iterator orig = *this;
        return ++(*this), orig;
    }

    runtime_view_iterator &operator--() ENTT_NOEXCEPT {
        while(--it != (*pools)[0]->begin() && !valid()) {}
        return *this;
    }

    runtime_view_iterator operator--(int) ENTT_NOEXCEPT {
        runtime_view_iterator orig = *this;
        return operator--(), orig;
    }

    [[nodiscard]] pointer operator->() const {
        return it.operator->();
    }

    [[nodiscard]] reference operator*() const {
        return *operator->();
    }

    [[nodiscard]] bool operator==(const runtime_view_iterator &other) const ENTT_NOEXCEPT {
        return it == other.it;
    }

    [[nodiscard]] bool operator!=(const runtime_view_iterator &other) const ENTT_NOEXCEPT {
        return !(*this == other);
    }

private:
    const std::vector<const Type *> *pools;
    const std::vector<const Type *> *filter;
    iterator_type it;
    bool tombstone_check;
};

} // namespace internal

/**
 * Internal details not to be documented.
 * @endcond
 */

/**
 * @brief Runtime view.
 *
 * Runtime views iterate over those entities that have at least all the given
 * components in their bags. During initialization, a runtime view looks at the
 * number of entities available for each component and picks up a reference to
 * the smallest set of candidate entities in order to get a performance boost
 * when iterate.

 * Order of elements during iterations are highly dependent on the order of the
 * underlying data structures. See sparse_set and its specializations for more
 * details.
 *
 * @b Important
 *
 * Iterators aren't invalidated if:
 *
 * * New instances of the given components are created and assigned to entities.
 * * The entity currently pointed is modified (as an example, if one of the
 *   given components is removed from the entity to which the iterator points).
 * * The entity currently pointed is destroyed.
 *
 * In all the other cases, modifying the pools of the given components in any
 * way invalidates all the iterators and using them results in undefined
 * behavior.
 *
 * @note
 * Views share references to the underlying data structures of the registry that
 * generated them. Therefore any change to the entities and to the components
 * made by means of the registry are immediately reflected by the views, unless
 * a pool was missing when the view was built (in this case, the view won't
 * have a valid reference and won't be updated accordingly).
 *
 * @warning
 * Lifetime of a view must not overcome that of the registry that generated it.
 * In any other case, attempting to use a view results in undefined behavior.
 *
 * @tparam Entity A valid entity type (see entt_traits for more details).
 */
template<typename Entity>
class basic_runtime_view final {
    using basic_common_type = basic_sparse_set<Entity>;

    [[nodiscard]] bool valid() const {
        return !pools.empty() && pools.front();
    }

public:
    /*! @brief Underlying entity identifier. */
    using entity_type = Entity;
    /*! @brief Unsigned integer type. */
    using size_type = std::size_t;
    /*! @brief Bidirectional iterator type. */
    using iterator = internal::runtime_view_iterator<basic_common_type>;

    /*! @brief Default constructor to use to create empty, invalid views. */
    basic_runtime_view() ENTT_NOEXCEPT
        : pools{},
          filter{} {}

    /**
     * @brief Constructs a runtime view from a set of storage classes.
     * @param cpools The storage for the types to iterate.
     * @param epools The storage for the types used to filter the view.
     */
    basic_runtime_view(std::vector<const basic_common_type *> cpools, std::vector<const basic_common_type *> epools) ENTT_NOEXCEPT
        : pools{std::move(cpools)},
          filter{std::move(epools)} {
        auto candidate = std::min_element(pools.begin(), pools.end(), [](const auto *lhs, const auto *rhs) {
            return (!lhs && rhs) || (lhs && rhs && lhs->size() < rhs->size());
        });

        // brings the best candidate (if any) on front of the vector
        std::rotate(pools.begin(), candidate, pools.end());
    }

    /**
     * @brief Estimates the number of entities iterated by the view.
     * @return Estimated number of entities iterated by the view.
     */
    [[nodiscard]] size_type size_hint() const {
        return valid() ? pools.front()->size() : size_type{};
    }

    /**
     * @brief Returns an iterator to the first entity that has the given
     * components.
     *
     * The returned iterator points to the first entity that has the given
     * components. If the view is empty, the returned iterator will be equal to
     * `end()`.
     *
     * @return An iterator to the first entity that has the given components.
     */
    [[nodiscard]] iterator begin() const {
        return valid() ? iterator{pools, filter, pools[0]->begin()} : iterator{};
    }

    /**
     * @brief Returns an iterator that is past the last entity that has the
     * given components.
     *
     * The returned iterator points to the entity following the last entity that
     * has the given components. Attempting to dereference the returned iterator
     * results in undefined behavior.
     *
     * @return An iterator to the entity following the last entity that has the
     * given components.
     */
    [[nodiscard]] iterator end() const {
        return valid() ? iterator{pools, filter, pools[0]->end()} : iterator{};
    }

    /**
     * @brief Checks if a view contains an entity.
     * @param entt A valid identifier.
     * @return True if the view contains the given entity, false otherwise.
     */
    [[nodiscard]] bool contains(const entity_type entt) const {
        return valid() && std::all_of(pools.cbegin(), pools.cend(), [entt](const auto *curr) { return curr->contains(entt); })
               && std::none_of(filter.cbegin(), filter.cend(), [entt](const auto *curr) { return curr && curr->contains(entt); });
    }

    /**
     * @brief Iterates entities and applies the given function object to them.
     *
     * The function object is invoked for each entity. It is provided only with
     * the entity itself. To get the components, users can use the registry with
     * which the view was built.

     * The signature of the function should be equivalent to the following:
     *
     * @code{.cpp}
     * void(const entity_type);
     * @endcode
     *
     * @tparam Func Type of the function object to invoke.
     * @param func A valid function object.
     */
    template<typename Func>
    void each(Func func) const {
        for(const auto entity: *this) {
            func(entity);
        }
    }

private:
    std::vector<const basic_common_type *> pools;
    std::vector<const basic_common_type *> filter;
};

} // namespace entt

#endif
<|endoftext|>


<commit_before>#include "GDBWindow.h"

#include <QGridLayout>
#include <QGroupBox>
#include <QLabel>
#include <QLineEdit>
#include <QPushButton>
#include <QVBoxLayout>

#include "GDBController.h"

using namespace QGBA;

GDBWindow::GDBWindow(GDBController* controller, QWidget* parent)
	: QWidget(parent)
	, m_gdbController(controller)
{
	setWindowFlags(windowFlags() & ~Qt::WindowFullscreenButtonHint);
	QVBoxLayout* mainSegment = new QVBoxLayout;
	setLayout(mainSegment);
	QGroupBox* settings = new QGroupBox(tr("Server settings"));
	mainSegment->addWidget(settings);

	QGridLayout* settingsGrid = new QGridLayout;
	settings->setLayout(settingsGrid);

	QLabel* portLabel = new QLabel(tr("Local port"));
	settingsGrid->addWidget(portLabel, 0, 0, Qt::AlignRight);
	QLabel* bindAddressLabel = new QLabel(tr("Bind address"));
	settingsGrid->addWidget(bindAddressLabel, 1, 0, Qt::AlignRight);

	m_portEdit = new QLineEdit("2345");
	m_portEdit->setMaxLength(5);
	connect(m_portEdit, SIGNAL(textChanged(const QString&)), this, SLOT(portChanged(const QString&)));
	settingsGrid->addWidget(m_portEdit, 0, 1, Qt::AlignLeft);

	m_bindAddressEdit = new QLineEdit("0.0.0.0");
	m_bindAddressEdit->setMaxLength(15);
	connect(m_bindAddressEdit, SIGNAL(textChanged(const QString&)), this, SLOT(bindAddressChanged(const QString&)));
	settingsGrid->addWidget(m_bindAddressEdit, 1, 1, Qt::AlignLeft);

	m_startStopButton = new QPushButton(tr("Start"));
	connect(m_startStopButton, SIGNAL(clicked()), m_gdbController, SLOT(listen()));
	connect(m_startStopButton, SIGNAL(clicked()), this, SLOT(started()));
	mainSegment->addWidget(m_startStopButton);
}

void GDBWindow::portChanged(const QString& portString) {
	bool ok = false;
	ushort port = portString.toUShort(&ok);
	if (ok) {
		m_gdbController->setPort(port);
	}
}

void GDBWindow::bindAddressChanged(const QString& bindAddressString) {
	bool ok = false;
	QStringList parts = bindAddressString.split('.');
	if (parts.length() != 4) {
		return;
	}
	int i;
	uint32_t address = 0;
	for (i = 0; i < 4; ++i) {
		ushort octet = parts[i].toUShort(&ok);
		if (!ok) {
			return;
		}
		if (octet > 0xFF) {
			return;
		}
		address <<= 8;
		address += octet;
	}
	m_gdbController->setBindAddress(address);
}

void GDBWindow::started() {
	m_portEdit->setEnabled(false);
	m_bindAddressEdit->setEnabled(false);
	m_startStopButton->setText(tr("Stop"));
	disconnect(m_startStopButton, SIGNAL(clicked()), m_gdbController, SLOT(listen()));
	disconnect(m_startStopButton, SIGNAL(clicked()), this, SLOT(started()));
	connect(m_startStopButton, SIGNAL(clicked()), m_gdbController, SLOT(detach()));
	connect(m_startStopButton, SIGNAL(clicked()), this, SLOT(stopped()));
}

void GDBWindow::stopped() {
	m_portEdit->setEnabled(true);
	m_bindAddressEdit->setEnabled(true);
	m_startStopButton->setText(tr("Start"));
	disconnect(m_startStopButton, SIGNAL(clicked()), m_gdbController, SLOT(detach()));
	disconnect(m_startStopButton, SIGNAL(clicked()), this, SLOT(stopped()));
	connect(m_startStopButton, SIGNAL(clicked()), m_gdbController, SLOT(listen()));
	connect(m_startStopButton, SIGNAL(clicked()), this, SLOT(started()));
}
<commit_msg>Make sure GDB window is created in sync with GDB server state<commit_after>#include "GDBWindow.h"

#include <QGridLayout>
#include <QGroupBox>
#include <QLabel>
#include <QLineEdit>
#include <QPushButton>
#include <QVBoxLayout>

#include "GDBController.h"

using namespace QGBA;

GDBWindow::GDBWindow(GDBController* controller, QWidget* parent)
	: QWidget(parent)
	, m_gdbController(controller)
{
	setWindowFlags(windowFlags() & ~Qt::WindowFullscreenButtonHint);
	QVBoxLayout* mainSegment = new QVBoxLayout;
	setLayout(mainSegment);
	QGroupBox* settings = new QGroupBox(tr("Server settings"));
	mainSegment->addWidget(settings);

	QGridLayout* settingsGrid = new QGridLayout;
	settings->setLayout(settingsGrid);

	QLabel* portLabel = new QLabel(tr("Local port"));
	settingsGrid->addWidget(portLabel, 0, 0, Qt::AlignRight);
	QLabel* bindAddressLabel = new QLabel(tr("Bind address"));
	settingsGrid->addWidget(bindAddressLabel, 1, 0, Qt::AlignRight);

	m_portEdit = new QLineEdit("2345");
	m_portEdit->setMaxLength(5);
	connect(m_portEdit, SIGNAL(textChanged(const QString&)), this, SLOT(portChanged(const QString&)));
	settingsGrid->addWidget(m_portEdit, 0, 1, Qt::AlignLeft);

	m_bindAddressEdit = new QLineEdit("0.0.0.0");
	m_bindAddressEdit->setMaxLength(15);
	connect(m_bindAddressEdit, SIGNAL(textChanged(const QString&)), this, SLOT(bindAddressChanged(const QString&)));
	settingsGrid->addWidget(m_bindAddressEdit, 1, 1, Qt::AlignLeft);

	m_startStopButton = new QPushButton;
	mainSegment->addWidget(m_startStopButton);
	if (m_gdbController->isAttached()) {
		started();
	} else {
		stopped();
	}
}

void GDBWindow::portChanged(const QString& portString) {
	bool ok = false;
	ushort port = portString.toUShort(&ok);
	if (ok) {
		m_gdbController->setPort(port);
	}
}

void GDBWindow::bindAddressChanged(const QString& bindAddressString) {
	bool ok = false;
	QStringList parts = bindAddressString.split('.');
	if (parts.length() != 4) {
		return;
	}
	int i;
	uint32_t address = 0;
	for (i = 0; i < 4; ++i) {
		ushort octet = parts[i].toUShort(&ok);
		if (!ok) {
			return;
		}
		if (octet > 0xFF) {
			return;
		}
		address <<= 8;
		address += octet;
	}
	m_gdbController->setBindAddress(address);
}

void GDBWindow::started() {
	m_portEdit->setEnabled(false);
	m_bindAddressEdit->setEnabled(false);
	m_startStopButton->setText(tr("Stop"));
	disconnect(m_startStopButton, SIGNAL(clicked()), m_gdbController, SLOT(listen()));
	disconnect(m_startStopButton, SIGNAL(clicked()), this, SLOT(started()));
	connect(m_startStopButton, SIGNAL(clicked()), m_gdbController, SLOT(detach()));
	connect(m_startStopButton, SIGNAL(clicked()), this, SLOT(stopped()));
}

void GDBWindow::stopped() {
	m_portEdit->setEnabled(true);
	m_bindAddressEdit->setEnabled(true);
	m_startStopButton->setText(tr("Start"));
	disconnect(m_startStopButton, SIGNAL(clicked()), m_gdbController, SLOT(detach()));
	disconnect(m_startStopButton, SIGNAL(clicked()), this, SLOT(stopped()));
	connect(m_startStopButton, SIGNAL(clicked()), m_gdbController, SLOT(listen()));
	connect(m_startStopButton, SIGNAL(clicked()), this, SLOT(started()));
}
<|endoftext|>


<commit_before><commit_msg>[spaces.constraints] update CRTP handling<commit_after><|endoftext|>


<commit_before><commit_msg>[test.test_common] silence warnings<commit_after><|endoftext|>


<commit_before>#ifndef STX_TYPE_INCLUDED
#define STX_TYPE_INCLUDED

#include <string>

#pragma once

namespace stx {

std::string demangle(const char* n);

template<class T>
std::string nameof(T const* t) { return demangle(typeid(*t).name()); }
template<class T>
std::string nameof(T const& t) { return demangle(typeid(*t).name()); }

} // namespace stx

#endif // header guard STX_TYPE_INCLUDED
<commit_msg>Fixed demangle(T&)<commit_after>#ifndef STX_TYPE_INCLUDED
#define STX_TYPE_INCLUDED

#include <string>

#pragma once

namespace stx {

std::string demangle(const char* n);

template<class T>
std::string nameof(T const* t) { return demangle(typeid(*t).name()); }
template<class T>
std::string nameof(T const& t) { return demangle(typeid(t).name()); }

} // namespace stx

#endif // header guard STX_TYPE_INCLUDED
<|endoftext|>


<commit_before>// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2013 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "clientversion.h"
#include "rpcserver.h"
#include "init.h"
#include "main.h"
#include "noui.h"
#include "ui_interface.h"
#include "util.h"

#include <boost/algorithm/string/predicate.hpp>
#include <boost/filesystem.hpp>
#include <boost/thread.hpp>

/* Introduction text for doxygen: */

/*! \mainpage Developer documentation
 *
 * \section intro_sec Introduction
 *
 * This is the developer documentation of the reference client for an experimental new digital currency called Bitcoin (http://www.bitcoin.org/),
 * which enables instant payments to anyone, anywhere in the world. Bitcoin uses peer-to-peer technology to operate
 * with no central authority: managing transactions and issuing money are carried out collectively by the network.
 *
 * The software is a community-driven open source project, released under the MIT license.
 *
 * \section Navigation
 * Use the buttons Namespaces, Classes or Files at the top of the page to start navigating the code.
 */

static bool fDaemon;

void DetectShutdownThread(boost::thread_group* threadGroup)
{
    bool fShutdown = ShutdownRequested();
    // Tell the main threads to shutdown.
    while (!fShutdown)
    {
        MilliSleep(200);
        fShutdown = ShutdownRequested();
    }
    if (threadGroup)
    {
        threadGroup->interrupt_all();
        threadGroup->join_all();
    }
}

//////////////////////////////////////////////////////////////////////////////
//
// Start
//
bool AppInit(int argc, char* argv[])
{
    boost::thread_group threadGroup;
    boost::thread* detectShutdownThread = NULL;

    bool fRet = false;

    //
    // Parameters
    //
    // If Qt is used, parameters/bitcoin.conf are parsed in qt/bitcoin.cpp's main()
    ParseParameters(argc, argv);

    // Process help and version before taking care about datadir
    if (mapArgs.count("-?") || mapArgs.count("-help") || mapArgs.count("-version"))
    {
        std::string strUsage = _("Litecoin Core Daemon") + " " + _("version") + " " + FormatFullVersion() + "\n";

        if (mapArgs.count("-version"))
        {
            strUsage += LicenseInfo();
        }
        else
        {
            strUsage += "\n" + _("Usage:") + "\n" +
                  "  litecoind [options]                     " + _("Start Liteocin Core Daemon") + "\n";

            strUsage += "\n" + HelpMessage(HMM_BITCOIND);
        }

        fprintf(stdout, "%s", strUsage.c_str());
        return false;
    }

    try
    {
        if (!boost::filesystem::is_directory(GetDataDir(false)))
        {
            fprintf(stderr, "Error: Specified data directory \"%s\" does not exist.\n", mapArgs["-datadir"].c_str());
            return false;
        }
        try
        {
            ReadConfigFile(mapArgs, mapMultiArgs);
        } catch(std::exception &e) {
            fprintf(stderr,"Error reading configuration file: %s\n", e.what());
            return false;
        }
        // Check for -testnet or -regtest parameter (Params() calls are only valid after this clause)
        if (!SelectParamsFromCommandLine()) {
            fprintf(stderr, "Error: Invalid combination of -regtest and -testnet.\n");
            return false;
        }

        // Command-line RPC
        bool fCommandLine = false;
        for (int i = 1; i < argc; i++)
            if (!IsSwitchChar(argv[i][0]) && !boost::algorithm::istarts_with(argv[i], "litecoin:"))
                fCommandLine = true;

        if (fCommandLine)
        {
            fprintf(stderr, "Error: There is no RPC client functionality in litecoind anymore. Use the litecoin-cli utility instead.\n");
            exit(1);
        }
#ifndef WIN32
        fDaemon = GetBoolArg("-daemon", false);
        if (fDaemon)
        {
            fprintf(stdout, "Litecoin server starting\n");

            // Daemonize
            pid_t pid = fork();
            if (pid < 0)
            {
                fprintf(stderr, "Error: fork() returned %d errno %d\n", pid, errno);
                return false;
            }
            if (pid > 0) // Parent process, pid is child process id
            {
                return true;
            }
            // Child process falls through to rest of initialization

            pid_t sid = setsid();
            if (sid < 0)
                fprintf(stderr, "Error: setsid() returned %d errno %d\n", sid, errno);
        }
#endif
        SoftSetBoolArg("-server", true);

        detectShutdownThread = new boost::thread(boost::bind(&DetectShutdownThread, &threadGroup));
        fRet = AppInit2(threadGroup);
    }
    catch (std::exception& e) {
        PrintExceptionContinue(&e, "AppInit()");
    } catch (...) {
        PrintExceptionContinue(NULL, "AppInit()");
    }

    if (!fRet)
    {
        if (detectShutdownThread)
            detectShutdownThread->interrupt();

        threadGroup.interrupt_all();
        // threadGroup.join_all(); was left out intentionally here, because we didn't re-test all of
        // the startup-failure cases to make sure they don't result in a hang due to some
        // thread-blocking-waiting-for-another-thread-during-startup case
    }

    if (detectShutdownThread)
    {
        detectShutdownThread->join();
        delete detectShutdownThread;
        detectShutdownThread = NULL;
    }
    Shutdown();

    return fRet;
}

int main(int argc, char* argv[])
{
    SetupEnvironment();

    // Connect bitcoind signal handlers
    noui_connect();

    return (AppInit(argc, argv) ? 0 : 1);
}
<commit_msg>fix typo (Liteocin -> Litecoin)<commit_after>// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2013 The Bitcoin developers
// Distributed under the MIT/X11 software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "clientversion.h"
#include "rpcserver.h"
#include "init.h"
#include "main.h"
#include "noui.h"
#include "ui_interface.h"
#include "util.h"

#include <boost/algorithm/string/predicate.hpp>
#include <boost/filesystem.hpp>
#include <boost/thread.hpp>

/* Introduction text for doxygen: */

/*! \mainpage Developer documentation
 *
 * \section intro_sec Introduction
 *
 * This is the developer documentation of the reference client for an experimental new digital currency called Bitcoin (http://www.bitcoin.org/),
 * which enables instant payments to anyone, anywhere in the world. Bitcoin uses peer-to-peer technology to operate
 * with no central authority: managing transactions and issuing money are carried out collectively by the network.
 *
 * The software is a community-driven open source project, released under the MIT license.
 *
 * \section Navigation
 * Use the buttons Namespaces, Classes or Files at the top of the page to start navigating the code.
 */

static bool fDaemon;

void DetectShutdownThread(boost::thread_group* threadGroup)
{
    bool fShutdown = ShutdownRequested();
    // Tell the main threads to shutdown.
    while (!fShutdown)
    {
        MilliSleep(200);
        fShutdown = ShutdownRequested();
    }
    if (threadGroup)
    {
        threadGroup->interrupt_all();
        threadGroup->join_all();
    }
}

//////////////////////////////////////////////////////////////////////////////
//
// Start
//
bool AppInit(int argc, char* argv[])
{
    boost::thread_group threadGroup;
    boost::thread* detectShutdownThread = NULL;

    bool fRet = false;

    //
    // Parameters
    //
    // If Qt is used, parameters/bitcoin.conf are parsed in qt/bitcoin.cpp's main()
    ParseParameters(argc, argv);

    // Process help and version before taking care about datadir
    if (mapArgs.count("-?") || mapArgs.count("-help") || mapArgs.count("-version"))
    {
        std::string strUsage = _("Litecoin Core Daemon") + " " + _("version") + " " + FormatFullVersion() + "\n";

        if (mapArgs.count("-version"))
        {
            strUsage += LicenseInfo();
        }
        else
        {
            strUsage += "\n" + _("Usage:") + "\n" +
                  "  litecoind [options]                     " + _("Start Litecoin Core Daemon") + "\n";

            strUsage += "\n" + HelpMessage(HMM_BITCOIND);
        }

        fprintf(stdout, "%s", strUsage.c_str());
        return false;
    }

    try
    {
        if (!boost::filesystem::is_directory(GetDataDir(false)))
        {
            fprintf(stderr, "Error: Specified data directory \"%s\" does not exist.\n", mapArgs["-datadir"].c_str());
            return false;
        }
        try
        {
            ReadConfigFile(mapArgs, mapMultiArgs);
        } catch(std::exception &e) {
            fprintf(stderr,"Error reading configuration file: %s\n", e.what());
            return false;
        }
        // Check for -testnet or -regtest parameter (Params() calls are only valid after this clause)
        if (!SelectParamsFromCommandLine()) {
            fprintf(stderr, "Error: Invalid combination of -regtest and -testnet.\n");
            return false;
        }

        // Command-line RPC
        bool fCommandLine = false;
        for (int i = 1; i < argc; i++)
            if (!IsSwitchChar(argv[i][0]) && !boost::algorithm::istarts_with(argv[i], "litecoin:"))
                fCommandLine = true;

        if (fCommandLine)
        {
            fprintf(stderr, "Error: There is no RPC client functionality in litecoind anymore. Use the litecoin-cli utility instead.\n");
            exit(1);
        }
#ifndef WIN32
        fDaemon = GetBoolArg("-daemon", false);
        if (fDaemon)
        {
            fprintf(stdout, "Litecoin server starting\n");

            // Daemonize
            pid_t pid = fork();
            if (pid < 0)
            {
                fprintf(stderr, "Error: fork() returned %d errno %d\n", pid, errno);
                return false;
            }
            if (pid > 0) // Parent process, pid is child process id
            {
                return true;
            }
            // Child process falls through to rest of initialization

            pid_t sid = setsid();
            if (sid < 0)
                fprintf(stderr, "Error: setsid() returned %d errno %d\n", sid, errno);
        }
#endif
        SoftSetBoolArg("-server", true);

        detectShutdownThread = new boost::thread(boost::bind(&DetectShutdownThread, &threadGroup));
        fRet = AppInit2(threadGroup);
    }
    catch (std::exception& e) {
        PrintExceptionContinue(&e, "AppInit()");
    } catch (...) {
        PrintExceptionContinue(NULL, "AppInit()");
    }

    if (!fRet)
    {
        if (detectShutdownThread)
            detectShutdownThread->interrupt();

        threadGroup.interrupt_all();
        // threadGroup.join_all(); was left out intentionally here, because we didn't re-test all of
        // the startup-failure cases to make sure they don't result in a hang due to some
        // thread-blocking-waiting-for-another-thread-during-startup case
    }

    if (detectShutdownThread)
    {
        detectShutdownThread->join();
        delete detectShutdownThread;
        detectShutdownThread = NULL;
    }
    Shutdown();

    return fRet;
}

int main(int argc, char* argv[])
{
    SetupEnvironment();

    // Connect bitcoind signal handlers
    noui_connect();

    return (AppInit(argc, argv) ? 0 : 1);
}
<|endoftext|>


<commit_before>/**
*  Copyright (C) 2019 3D Repo Ltd
*
*  This program is free software: you can redistribute it and/or modify
*  it under the terms of the GNU Affero General Public License as
*  published by the Free Software Foundation, either version 3 of the
*  License, or (at your option) any later version.
*
*  This program is distributed in the hope that it will be useful,
*  but WITHOUT ANY WARRANTY; without even the implied warranty of
*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*  GNU Affero General Public License for more details.
*
*  You should have received a copy of the GNU Affero General Public License
*  along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
#include <regex>
#include "repo_file_manager.h"
#include "../../../lib/repo_exception.h"
#include "../../model/repo_model_global.h"
#include "../../model/bson/repo_bson_factory.h"
#include "repo_file_handler_fs.h"
#include "repo_file_handler_gridfs.h"
#include "repo_file_handler_s3.h"

using namespace repo::core::handler::fileservice;

FileManager* FileManager::manager = nullptr;

FileManager* FileManager::getManager() {
	if (!manager) throw repo::lib::RepoException("Trying to get File manager before it's instantiated!");

	return manager;
}

FileManager* FileManager::instantiateManager(
	const repo::lib::RepoConfig &config,
	repo::core::handler::AbstractDatabaseHandler *dbHandler
){
	if (manager) disconnect();

	return manager = new FileManager(config, dbHandler);
}

bool FileManager::uploadFileAndCommit(
	const std::string                            &databaseName,
	const std::string                            &collectionNamePrefix,
	const std::string                            &fileName,
	const std::vector<uint8_t>                   &bin)
{
	bool success = true;
	auto fileUUID = repo::lib::RepoUUID::createUUID();
	auto linkName = defaultHandler->uploadFile(databaseName, collectionNamePrefix, fileUUID.toString(), bin);
	if (!linkName.empty()){

		success = upsertFileRef(
			databaseName,
			collectionNamePrefix,
			cleanFileName(fileName),
			linkName,
			defaultHandler->getType(),
			bin.size());
	}

	return success;
}

bool FileManager::deleteFileAndRef(
	const std::string                            &databaseName,
	const std::string                            &collectionNamePrefix,
	const std::string                            &fileName)
{
	bool success = true;
	repo::core::model::RepoBSON criteria = BSON(REPO_LABEL_ID << cleanFileName(fileName));
	repo::core::model::RepoRef ref = dbHandler->findOneByCriteria(
		databaseName,
		collectionNamePrefix + "." + REPO_COLLECTION_EXT_REF,
		criteria);

	if (ref.isEmpty())
	{
		repoTrace << "Failed: cannot find file ref "
			<< cleanFileName(fileName) << " from "
			<< databaseName << "/"
			<< collectionNamePrefix << "." << REPO_COLLECTION_EXT_REF;
		success = false;
	}
	else
	{
		const auto keyName = ref.getRefLink();
		const auto type = ref.getType(); //Should return enum

		std::shared_ptr<AbstractFileHandler> handler = gridfsHandler;;
		switch (type) {
		case repo::core::model::RepoRef::RefType::S3:
			handler = s3Handler;
			break;
		case repo::core::model::RepoRef::RefType::FS:
			handler = fsHandler;
			break;
		}

		if (handler) {
			success = defaultHandler->deleteFile(databaseName, collectionNamePrefix, keyName) &&
				dropFileRef(
					ref,
					databaseName,
					collectionNamePrefix);
		}
		else {
			repoError << "Trying to delete a file from " << repo::core::model::RepoRef::convertTypeAsString(type) << " but connection to this service is not configured.";
			success = false;
		}
	}

	return success;
}

FileManager::FileManager(
	const repo::lib::RepoConfig &config,
	repo::core::handler::AbstractDatabaseHandler *dbHandler
) : dbHandler(dbHandler) {

	if(!dbHandler)
		throw repo::lib::RepoException("Trying to instantiate FileManager with a nullptr to database!");

	gridfsHandler = std::make_shared<GridFSFileHandler>(dbHandler);
	defaultHandler = gridfsHandler;
#ifdef S3_SUPPORT
	auto s3Config = config.getS3Config();
	if (s3Config.configured) {
		s3Handler = std::make_shared<S3FileHandler>(s3Config.bucketName, s3Config.bucketRegion);
		if (config.getDefaultStorageEngine() == repo::lib::RepoConfig::FileStorageEngine::S3)
			defaultHandler = s3Handler;
	}
#endif

	auto fsConfig = config.getFSConfig();
	if (fsConfig.configured) {
		fsHandler = std::make_shared<FSFileHandler>(fsConfig.dir, fsConfig.nLevel);
		if (config.getDefaultStorageEngine() == repo::lib::RepoConfig::FileStorageEngine::FS)
			defaultHandler = fsHandler;
	}
}

std::string FileManager::cleanFileName(
	const std::string &fileName)
{
	std::string result;
	std::regex matchAllSlashes("(.*\/)+");
	std::regex matchUpToRevision(".*revision\/");

	result = std::regex_replace(fileName, matchUpToRevision, "");

	if (fileName.length() == result.length())
		result = std::regex_replace(fileName, matchAllSlashes, "");

	return result;
}

bool FileManager::dropFileRef(
	const repo::core::model::RepoBSON            bson,
	const std::string                            &databaseName,
	const std::string                            &collectionNamePrefix)
{
	std::string errMsg;
	bool success = true;

	std::string collectionName = collectionNamePrefix + "." + REPO_COLLECTION_EXT_REF;

	if (success = dbHandler->dropDocument(bson, databaseName, collectionName, errMsg))
	{
		repoInfo << "File ref for " << collectionName << " dropped.";
	}
	else
	{
		repoError << "Failed to drop " << collectionName << " file ref: " << errMsg;;
	}

	return success;
}

bool FileManager::upsertFileRef(
	const std::string                            &databaseName,
	const std::string                            &collectionNamePrefix,
	const std::string                            &id,
	const std::string                            &link,
	const repo::core::model::RepoRef::RefType    &type,
	const uint32_t                               &size)
{
	std::string errMsg;
	bool success = true;

	auto refObj = repo::core::model::RepoBSONFactory::makeRepoRef(id, type, link, size);
	std::string collectionName = collectionNamePrefix + "." + REPO_COLLECTION_EXT_REF;

	if (success = dbHandler->upsertDocument(databaseName, collectionName, refObj, true, errMsg))
	{
		repoInfo << "File ref for " << collectionName << " added.";
	}
	else
	{
		repoError << "Failed to add " << collectionName << " file ref: " << errMsg;;
	}

	return success;
}
<commit_msg>ISSUE #320 make a copy to gridfs as legacy suport<commit_after>/**
*  Copyright (C) 2019 3D Repo Ltd
*
*  This program is free software: you can redistribute it and/or modify
*  it under the terms of the GNU Affero General Public License as
*  published by the Free Software Foundation, either version 3 of the
*  License, or (at your option) any later version.
*
*  This program is distributed in the hope that it will be useful,
*  but WITHOUT ANY WARRANTY; without even the implied warranty of
*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*  GNU Affero General Public License for more details.
*
*  You should have received a copy of the GNU Affero General Public License
*  along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
#include <regex>
#include "repo_file_manager.h"
#include "../../../lib/repo_exception.h"
#include "../../model/repo_model_global.h"
#include "../../model/bson/repo_bson_factory.h"
#include "repo_file_handler_fs.h"
#include "repo_file_handler_gridfs.h"
#include "repo_file_handler_s3.h"

using namespace repo::core::handler::fileservice;

#define LEGACY_SUPPORT 1

FileManager* FileManager::manager = nullptr;

FileManager* FileManager::getManager() {
	if (!manager) throw repo::lib::RepoException("Trying to get File manager before it's instantiated!");

	return manager;
}

FileManager* FileManager::instantiateManager(
	const repo::lib::RepoConfig &config,
	repo::core::handler::AbstractDatabaseHandler *dbHandler
){
	if (manager) disconnect();

	return manager = new FileManager(config, dbHandler);
}

bool FileManager::uploadFileAndCommit(
	const std::string                            &databaseName,
	const std::string                            &collectionNamePrefix,
	const std::string                            &fileName,
	const std::vector<uint8_t>                   &bin)
{
	bool success = true;
	auto fileUUID = repo::lib::RepoUUID::createUUID();
	auto linkName = defaultHandler->uploadFile(databaseName, collectionNamePrefix, fileUUID.toString(), bin);
	if (!linkName.empty()){

		success = upsertFileRef(
			databaseName,
			collectionNamePrefix,
			cleanFileName(fileName),
			linkName,
			defaultHandler->getType(),
			bin.size());
#ifdef LEGACY_SUPPORT
		gridfsHandler->uploadFile(databaseName, collectionNamePrefix, fileUUID.toString(), bin);
#endif
	}

	return success;
}

bool FileManager::deleteFileAndRef(
	const std::string                            &databaseName,
	const std::string                            &collectionNamePrefix,
	const std::string                            &fileName)
{
	bool success = true;
	repo::core::model::RepoBSON criteria = BSON(REPO_LABEL_ID << cleanFileName(fileName));
	repo::core::model::RepoRef ref = dbHandler->findOneByCriteria(
		databaseName,
		collectionNamePrefix + "." + REPO_COLLECTION_EXT_REF,
		criteria);

#ifdef LEGACY_SUPPORT
	gridfsHandler->deleteFile(databaseName, collectionNamePrefix, fileName);
#endif

	if (ref.isEmpty())
	{
		repoTrace << "Failed: cannot find file ref "
			<< cleanFileName(fileName) << " from "
			<< databaseName << "/"
			<< collectionNamePrefix << "." << REPO_COLLECTION_EXT_REF;
		success = false;
	}
	else
	{
		const auto keyName = ref.getRefLink();
		const auto type = ref.getType(); //Should return enum

		std::shared_ptr<AbstractFileHandler> handler = gridfsHandler;;
		switch (type) {
		case repo::core::model::RepoRef::RefType::S3:
			handler = s3Handler;
			break;
		case repo::core::model::RepoRef::RefType::FS:
			handler = fsHandler;
			break;
		}

		if (handler) {
			success = defaultHandler->deleteFile(databaseName, collectionNamePrefix, keyName) &&
				dropFileRef(
					ref,
					databaseName,
					collectionNamePrefix);
		}
		else {
			repoError << "Trying to delete a file from " << repo::core::model::RepoRef::convertTypeAsString(type) << " but connection to this service is not configured.";
			success = false;
		}
	}

	return success;
}

FileManager::FileManager(
	const repo::lib::RepoConfig &config,
	repo::core::handler::AbstractDatabaseHandler *dbHandler
) : dbHandler(dbHandler) {

	if(!dbHandler)
		throw repo::lib::RepoException("Trying to instantiate FileManager with a nullptr to database!");

	gridfsHandler = std::make_shared<GridFSFileHandler>(dbHandler);
	defaultHandler = gridfsHandler;
#ifdef S3_SUPPORT
	auto s3Config = config.getS3Config();
	if (s3Config.configured) {
		s3Handler = std::make_shared<S3FileHandler>(s3Config.bucketName, s3Config.bucketRegion);
		if (config.getDefaultStorageEngine() == repo::lib::RepoConfig::FileStorageEngine::S3)
			defaultHandler = s3Handler;
	}
#endif

	auto fsConfig = config.getFSConfig();
	if (fsConfig.configured) {
		fsHandler = std::make_shared<FSFileHandler>(fsConfig.dir, fsConfig.nLevel);
		if (config.getDefaultStorageEngine() == repo::lib::RepoConfig::FileStorageEngine::FS)
			defaultHandler = fsHandler;
	}
}

std::string FileManager::cleanFileName(
	const std::string &fileName)
{
	std::string result;
	std::regex matchAllSlashes("(.*\/)+");
	std::regex matchUpToRevision(".*revision\/");

	result = std::regex_replace(fileName, matchUpToRevision, "");

	if (fileName.length() == result.length())
		result = std::regex_replace(fileName, matchAllSlashes, "");

	return result;
}

bool FileManager::dropFileRef(
	const repo::core::model::RepoBSON            bson,
	const std::string                            &databaseName,
	const std::string                            &collectionNamePrefix)
{
	std::string errMsg;
	bool success = true;

	std::string collectionName = collectionNamePrefix + "." + REPO_COLLECTION_EXT_REF;

	if (success = dbHandler->dropDocument(bson, databaseName, collectionName, errMsg))
	{
		repoInfo << "File ref for " << collectionName << " dropped.";
	}
	else
	{
		repoError << "Failed to drop " << collectionName << " file ref: " << errMsg;;
	}

	return success;
}

bool FileManager::upsertFileRef(
	const std::string                            &databaseName,
	const std::string                            &collectionNamePrefix,
	const std::string                            &id,
	const std::string                            &link,
	const repo::core::model::RepoRef::RefType    &type,
	const uint32_t                               &size)
{
	std::string errMsg;
	bool success = true;

	auto refObj = repo::core::model::RepoBSONFactory::makeRepoRef(id, type, link, size);
	std::string collectionName = collectionNamePrefix + "." + REPO_COLLECTION_EXT_REF;

	if (success = dbHandler->upsertDocument(databaseName, collectionName, refObj, true, errMsg))
	{
		repoInfo << "File ref for " << collectionName << " added.";
	}
	else
	{
		repoError << "Failed to add " << collectionName << " file ref: " << errMsg;;
	}

	return success;
}
<|endoftext|>


<commit_before>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// A general interface for filtering and only acting on classes in Chromium C++
// code.

#include "ChromeClassTester.h"

#include <sys/param.h>

using namespace clang;

namespace {

bool starts_with(const std::string& one, const std::string& two) {
  return one.substr(0, two.size()) == two;
}

bool ends_with(const std::string& one, const std::string& two) {
  if (two.size() > one.size())
    return false;

  return one.substr(one.size() - two.size(), two.size()) == two;
}

}  // namespace

ChromeClassTester::ChromeClassTester(CompilerInstance& instance)
    : instance_(instance),
      diagnostic_(instance.getDiagnostics()) {
  FigureOutSrcRoot();
  BuildBannedLists();
}

void ChromeClassTester::FigureOutSrcRoot() {
  char c_cwd[MAXPATHLEN];
  if (getcwd(c_cwd, MAXPATHLEN) > 0) {
    size_t pos = 1;
    std::string cwd = c_cwd;

    // Add a trailing '/' because the search below requires it.
    if (cwd[cwd.size() - 1] != '/')
      cwd += '/';

    // Search the directory tree downwards until we find a path that contains
    // "build/common.gypi" and assume that that is our srcroot.
    size_t next_slash = cwd.find('/', pos);
    while (next_slash != std::string::npos) {
      next_slash++;
      std::string candidate = cwd.substr(0, next_slash);

      if (ends_with(candidate, "src/")) {
        std::string common = candidate + "build/common.gypi";
        if (access(common.c_str(), F_OK) != -1) {
          src_root_ = candidate;
          break;
        }
      }

      pos = next_slash;
      next_slash = cwd.find('/', pos);
    }
  }

  if (src_root_.empty()) {
    unsigned id = diagnostic().getCustomDiagID(
        Diagnostic::Error,
        "WARNING: Can't figure out srcroot!\n");
    diagnostic().Report(id);
  }
}

void ChromeClassTester::BuildBannedLists() {
  banned_namespaces_.push_back("std");
  banned_namespaces_.push_back("__gnu_cxx");

  banned_directories_.push_back("third_party");
  banned_directories_.push_back("native_client");
  banned_directories_.push_back("breakpad");
  banned_directories_.push_back("courgette");
  banned_directories_.push_back("ppapi");
  banned_directories_.push_back("/usr");
  banned_directories_.push_back("testing");
  banned_directories_.push_back("googleurl");
  banned_directories_.push_back("v8");
  banned_directories_.push_back("sdch");

  // You are standing in a mazy of twisty dependencies, all resolved by
  // putting everything in the header.
  banned_directories_.push_back("chrome/test/automation");

  // Used in really low level threading code that probably shouldn't be out of
  // lined.
  ignored_record_names_.push_back("ThreadLocalBoolean");

  // A complicated pickle derived struct that is all packed integers.
  ignored_record_names_.push_back("Header");

  // Part of the GPU system that uses multiple included header
  // weirdness. Never getting this right.
  ignored_record_names_.push_back("Validators");

  // RAII class that's simple enough (media/base/callback.h).
  ignored_record_names_.push_back("AutoTaskRunner");
  ignored_record_names_.push_back("AutoCallbackRunner");

  // Has a UNIT_TEST only constructor. Isn't *terribly* complex...
  ignored_record_names_.push_back("AutocompleteController");
  ignored_record_names_.push_back("HistoryURLProvider");

  // Because of chrome frame
  ignored_record_names_.push_back("ReliabilityTestSuite");

  // Used over in the net unittests. A large enough bundle of integers with 1
  // non-pod class member. Probably harmless.
  ignored_record_names_.push_back("MockTransaction");

  // Used heavily in app_unittests and once in views_unittests. Fixing this
  // isn't worth the overhead of an additional library.
  ignored_record_names_.push_back("TestAnimationDelegate");

  // Part of our public interface that nacl and friends use. (Arguably, this
  // should mean that this is a higher priority but fixing this looks hard.)
  ignored_record_names_.push_back("PluginVersionInfo");
}

ChromeClassTester::~ChromeClassTester() {}

void ChromeClassTester::HandleTagDeclDefinition(TagDecl* tag) {
  if (CXXRecordDecl* record = dyn_cast<CXXRecordDecl>(tag)) {
    // If this is a POD or a class template or a type dependent on a
    // templated class, assume there's no ctor/dtor/virtual method
    // optimization that we can do.
    if (record->isPOD() ||
        record->getDescribedClassTemplate() ||
        record->getTemplateSpecializationKind() ||
        record->isDependentType())
      return;

    if (InBannedNamespace(record))
      return;

    SourceLocation record_location = record->getInnerLocStart();
    if (InBannedDirectory(record_location))
      return;

    // We sadly need to maintain a blacklist of types that violate these
    // rules, but do so for good reason or due to limitations of this
    // checker (i.e., we don't handle extern templates very well).
    std::string base_name = record->getNameAsString();
    if (IsIgnoredType(base_name))
      return;

    // We ignore all classes that end with "Matcher" because they're probably
    // GMock artifacts.
    if (ends_with(base_name, "Matcher"))
        return;

    CheckChromeClass(record_location, record);
  }
}

void ChromeClassTester::emitWarning(SourceLocation loc, const char* raw_error) {
  FullSourceLoc full(loc, instance().getSourceManager());
  std::string err;
  err = "[chromium-style] ";
  err += raw_error;
  Diagnostic::Level level =
      diagnostic().getWarningsAsErrors() ?
      Diagnostic::Error :
      Diagnostic::Warning;
  unsigned id = diagnostic().getCustomDiagID(level, err);
  DiagnosticBuilder B = diagnostic().Report(full, id);
}

bool ChromeClassTester::InTestingNamespace(Decl* record) {
  return GetNamespace(record).find("testing") != std::string::npos;
}

bool ChromeClassTester::InBannedNamespace(Decl* record) {
  std::string n = GetNamespace(record);
  if (n != "") {
    return std::find(banned_namespaces_.begin(), banned_namespaces_.end(), n)
        != banned_namespaces_.end();
  }

  return false;
}

std::string ChromeClassTester::GetNamespace(Decl* record) {
  return GetNamespaceImpl(record->getDeclContext(), "");
}

std::string ChromeClassTester::GetNamespaceImpl(const DeclContext* context,
                                                std::string candidate) {
  switch (context->getDeclKind()) {
    case Decl::TranslationUnit: {
      return candidate;
    }
    case Decl::Namespace: {
      const NamespaceDecl* decl = dyn_cast<NamespaceDecl>(context);
      std::string name_str;
      llvm::raw_string_ostream OS(name_str);
      if (decl->isAnonymousNamespace())
        OS << "<anonymous namespace>";
      else
        OS << decl;
      return GetNamespaceImpl(context->getParent(),
                              OS.str());
    }
    default: {
      return GetNamespaceImpl(context->getParent(), candidate);
    }
  }
}

bool ChromeClassTester::InBannedDirectory(const SourceLocation& loc) {
  if (loc.isFileID() && loc.isValid()) {
    bool invalid = false;
    const char* buffer_name = instance_.getSourceManager().getBufferName(
        loc, &invalid);
    if (!invalid && buffer_name) {
      std::string b(buffer_name);

      // Don't complain about these things in implementation files.
      if (ends_with(b, ".cc") || ends_with(b, ".cpp") || ends_with(b, ".mm")) {
        return true;
      }

      // Don't complain about autogenerated protobuf files.
      if (ends_with(b, ".pb.h")) {
        return true;
      }

      // We need to munge the paths so that they are relative to the repository
      // srcroot. We first resolve the symlinktastic relative path and then
      // remove our known srcroot from it if needed.
      char resolvedPath[MAXPATHLEN];
      if (realpath(b.c_str(), resolvedPath)) {
        std::string resolved = resolvedPath;
        if (starts_with(resolved, src_root_)) {
          b = resolved.substr(src_root_.size());
        }
      }

      for (std::vector<std::string>::const_iterator it =
               banned_directories_.begin();
           it != banned_directories_.end(); ++it) {
        if (starts_with(b, *it))
          return true;
      }
    }
  }

  return false;
}

bool ChromeClassTester::IsIgnoredType(const std::string& base_name) {
  for (std::vector<std::string>::const_iterator it =
           ignored_record_names_.begin();
       it != ignored_record_names_.end(); ++it) {
    if (base_name == *it)
      return true;
  }

  return false;
}
<commit_msg>Ignore autogenerated headers in clang.<commit_after>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// A general interface for filtering and only acting on classes in Chromium C++
// code.

#include "ChromeClassTester.h"

#include <sys/param.h>

using namespace clang;

namespace {

bool starts_with(const std::string& one, const std::string& two) {
  return one.substr(0, two.size()) == two;
}

bool ends_with(const std::string& one, const std::string& two) {
  if (two.size() > one.size())
    return false;

  return one.substr(one.size() - two.size(), two.size()) == two;
}

}  // namespace

ChromeClassTester::ChromeClassTester(CompilerInstance& instance)
    : instance_(instance),
      diagnostic_(instance.getDiagnostics()) {
  FigureOutSrcRoot();
  BuildBannedLists();
}

void ChromeClassTester::FigureOutSrcRoot() {
  char c_cwd[MAXPATHLEN];
  if (getcwd(c_cwd, MAXPATHLEN) > 0) {
    size_t pos = 1;
    std::string cwd = c_cwd;

    // Add a trailing '/' because the search below requires it.
    if (cwd[cwd.size() - 1] != '/')
      cwd += '/';

    // Search the directory tree downwards until we find a path that contains
    // "build/common.gypi" and assume that that is our srcroot.
    size_t next_slash = cwd.find('/', pos);
    while (next_slash != std::string::npos) {
      next_slash++;
      std::string candidate = cwd.substr(0, next_slash);

      if (ends_with(candidate, "src/")) {
        std::string common = candidate + "build/common.gypi";
        if (access(common.c_str(), F_OK) != -1) {
          src_root_ = candidate;
          break;
        }
      }

      pos = next_slash;
      next_slash = cwd.find('/', pos);
    }
  }

  if (src_root_.empty()) {
    unsigned id = diagnostic().getCustomDiagID(
        Diagnostic::Error,
        "WARNING: Can't figure out srcroot!\n");
    diagnostic().Report(id);
  }
}

void ChromeClassTester::BuildBannedLists() {
  banned_namespaces_.push_back("std");
  banned_namespaces_.push_back("__gnu_cxx");

  banned_directories_.push_back("third_party");
  banned_directories_.push_back("native_client");
  banned_directories_.push_back("breakpad");
  banned_directories_.push_back("courgette");
  banned_directories_.push_back("ppapi");
  banned_directories_.push_back("/usr");
  banned_directories_.push_back("testing");
  banned_directories_.push_back("googleurl");
  banned_directories_.push_back("v8");
  banned_directories_.push_back("sdch");

  // Don't check autogenerated headers.
  banned_directories_.push_back("out");

  // You are standing in a mazy of twisty dependencies, all resolved by
  // putting everything in the header.
  banned_directories_.push_back("chrome/test/automation");

  // Used in really low level threading code that probably shouldn't be out of
  // lined.
  ignored_record_names_.push_back("ThreadLocalBoolean");

  // A complicated pickle derived struct that is all packed integers.
  ignored_record_names_.push_back("Header");

  // Part of the GPU system that uses multiple included header
  // weirdness. Never getting this right.
  ignored_record_names_.push_back("Validators");

  // RAII class that's simple enough (media/base/callback.h).
  ignored_record_names_.push_back("AutoTaskRunner");
  ignored_record_names_.push_back("AutoCallbackRunner");

  // Has a UNIT_TEST only constructor. Isn't *terribly* complex...
  ignored_record_names_.push_back("AutocompleteController");
  ignored_record_names_.push_back("HistoryURLProvider");

  // Because of chrome frame
  ignored_record_names_.push_back("ReliabilityTestSuite");

  // Used over in the net unittests. A large enough bundle of integers with 1
  // non-pod class member. Probably harmless.
  ignored_record_names_.push_back("MockTransaction");

  // Used heavily in app_unittests and once in views_unittests. Fixing this
  // isn't worth the overhead of an additional library.
  ignored_record_names_.push_back("TestAnimationDelegate");

  // Part of our public interface that nacl and friends use. (Arguably, this
  // should mean that this is a higher priority but fixing this looks hard.)
  ignored_record_names_.push_back("PluginVersionInfo");
}

ChromeClassTester::~ChromeClassTester() {}

void ChromeClassTester::HandleTagDeclDefinition(TagDecl* tag) {
  if (CXXRecordDecl* record = dyn_cast<CXXRecordDecl>(tag)) {
    // If this is a POD or a class template or a type dependent on a
    // templated class, assume there's no ctor/dtor/virtual method
    // optimization that we can do.
    if (record->isPOD() ||
        record->getDescribedClassTemplate() ||
        record->getTemplateSpecializationKind() ||
        record->isDependentType())
      return;

    if (InBannedNamespace(record))
      return;

    SourceLocation record_location = record->getInnerLocStart();
    if (InBannedDirectory(record_location))
      return;

    // We sadly need to maintain a blacklist of types that violate these
    // rules, but do so for good reason or due to limitations of this
    // checker (i.e., we don't handle extern templates very well).
    std::string base_name = record->getNameAsString();
    if (IsIgnoredType(base_name))
      return;

    // We ignore all classes that end with "Matcher" because they're probably
    // GMock artifacts.
    if (ends_with(base_name, "Matcher"))
        return;

    CheckChromeClass(record_location, record);
  }
}

void ChromeClassTester::emitWarning(SourceLocation loc, const char* raw_error) {
  FullSourceLoc full(loc, instance().getSourceManager());
  std::string err;
  err = "[chromium-style] ";
  err += raw_error;
  Diagnostic::Level level =
      diagnostic().getWarningsAsErrors() ?
      Diagnostic::Error :
      Diagnostic::Warning;
  unsigned id = diagnostic().getCustomDiagID(level, err);
  DiagnosticBuilder B = diagnostic().Report(full, id);
}

bool ChromeClassTester::InTestingNamespace(Decl* record) {
  return GetNamespace(record).find("testing") != std::string::npos;
}

bool ChromeClassTester::InBannedNamespace(Decl* record) {
  std::string n = GetNamespace(record);
  if (n != "") {
    return std::find(banned_namespaces_.begin(), banned_namespaces_.end(), n)
        != banned_namespaces_.end();
  }

  return false;
}

std::string ChromeClassTester::GetNamespace(Decl* record) {
  return GetNamespaceImpl(record->getDeclContext(), "");
}

std::string ChromeClassTester::GetNamespaceImpl(const DeclContext* context,
                                                std::string candidate) {
  switch (context->getDeclKind()) {
    case Decl::TranslationUnit: {
      return candidate;
    }
    case Decl::Namespace: {
      const NamespaceDecl* decl = dyn_cast<NamespaceDecl>(context);
      std::string name_str;
      llvm::raw_string_ostream OS(name_str);
      if (decl->isAnonymousNamespace())
        OS << "<anonymous namespace>";
      else
        OS << decl;
      return GetNamespaceImpl(context->getParent(),
                              OS.str());
    }
    default: {
      return GetNamespaceImpl(context->getParent(), candidate);
    }
  }
}

bool ChromeClassTester::InBannedDirectory(const SourceLocation& loc) {
  if (loc.isFileID() && loc.isValid()) {
    bool invalid = false;
    const char* buffer_name = instance_.getSourceManager().getBufferName(
        loc, &invalid);
    if (!invalid && buffer_name) {
      std::string b(buffer_name);

      // Don't complain about these things in implementation files.
      if (ends_with(b, ".cc") || ends_with(b, ".cpp") || ends_with(b, ".mm")) {
        return true;
      }

      // Don't complain about autogenerated protobuf files.
      if (ends_with(b, ".pb.h")) {
        return true;
      }

      // We need to munge the paths so that they are relative to the repository
      // srcroot. We first resolve the symlinktastic relative path and then
      // remove our known srcroot from it if needed.
      char resolvedPath[MAXPATHLEN];
      if (realpath(b.c_str(), resolvedPath)) {
        std::string resolved = resolvedPath;
        if (starts_with(resolved, src_root_)) {
          b = resolved.substr(src_root_.size());
        }
      }

      for (std::vector<std::string>::const_iterator it =
               banned_directories_.begin();
           it != banned_directories_.end(); ++it) {
        if (starts_with(b, *it))
          return true;
      }
    }
  }

  return false;
}

bool ChromeClassTester::IsIgnoredType(const std::string& base_name) {
  for (std::vector<std::string>::const_iterator it =
           ignored_record_names_.begin();
       it != ignored_record_names_.end(); ++it) {
    if (base_name == *it)
      return true;
  }

  return false;
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2004-2005 The Regents of The University of Michigan
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * 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;
 * neither the name of the copyright holders 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
 * OWNER 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.
 *
 * Authors: Kevin Lim
 */

#include "arch/types.hh"
#include "arch/isa_traits.hh"
#include "base/trace.hh"
#include "base/traceflags.hh"
#include "cpu/o3/bpred_unit.hh"

template<class Impl>
BPredUnit<Impl>::BPredUnit(Params *params)
  : BTB(params->BTBEntries,
        params->BTBTagSize,
        params->instShiftAmt)
{
    // Setup the selected predictor.
    if (params->predType == "local") {
        localBP = new LocalBP(params->localPredictorSize,
                              params->localCtrBits,
                              params->instShiftAmt);
        predictor = Local;
    } else if (params->predType == "tournament") {
        tournamentBP = new TournamentBP(params->localPredictorSize,
                                        params->localCtrBits,
                                        params->localHistoryTableSize,
                                        params->localHistoryBits,
                                        params->globalPredictorSize,
                                        params->globalHistoryBits,
                                        params->globalCtrBits,
                                        params->choicePredictorSize,
                                        params->choiceCtrBits,
                                        params->instShiftAmt);
        predictor = Tournament;
    } else {
        fatal("Invalid BP selected!");
    }

    for (int i=0; i < Impl::MaxThreads; i++)
        RAS[i].init(params->RASSize);
}

template <class Impl>
void
BPredUnit<Impl>::regStats()
{
    lookups
        .name(name() + ".BPredUnit.lookups")
        .desc("Number of BP lookups")
        ;

    condPredicted
        .name(name() + ".BPredUnit.condPredicted")
        .desc("Number of conditional branches predicted")
        ;

    condIncorrect
        .name(name() + ".BPredUnit.condIncorrect")
        .desc("Number of conditional branches incorrect")
        ;

    BTBLookups
        .name(name() + ".BPredUnit.BTBLookups")
        .desc("Number of BTB lookups")
        ;

    BTBHits
        .name(name() + ".BPredUnit.BTBHits")
        .desc("Number of BTB hits")
        ;

    BTBCorrect
        .name(name() + ".BPredUnit.BTBCorrect")
        .desc("Number of correct BTB predictions (this stat may not "
              "work properly.")
        ;

    usedRAS
        .name(name() + ".BPredUnit.usedRAS")
        .desc("Number of times the RAS was used to get a target.")
        ;

    RASIncorrect
        .name(name() + ".BPredUnit.RASInCorrect")
        .desc("Number of incorrect RAS predictions.")
        ;
}

template <class Impl>
void
BPredUnit<Impl>::switchOut()
{
    // Clear any state upon switch out.
    for (int i = 0; i < Impl::MaxThreads; ++i) {
        squash(0, i);
    }
}

template <class Impl>
void
BPredUnit<Impl>::takeOverFrom()
{
    // Can reset all predictor state, but it's not necessarily better
    // than leaving it be.
/*
    for (int i = 0; i < Impl::MaxThreads; ++i)
        RAS[i].reset();

    BP.reset();
    BTB.reset();
*/
}

template <class Impl>
bool
BPredUnit<Impl>::predict(DynInstPtr &inst, Addr &PC, unsigned tid)
{
    // See if branch predictor predicts taken.
    // If so, get its target addr either from the BTB or the RAS.
    // Save off record of branch stuff so the RAS can be fixed
    // up once it's done.

    using TheISA::MachInst;

    bool pred_taken = false;
    Addr target;

    ++lookups;

    void *bp_history = NULL;

    if (inst->isUncondCtrl()) {
        DPRINTF(Fetch, "BranchPred: [tid:%i]: Unconditional control.\n", tid);
        pred_taken = true;
        // Tell the BP there was an unconditional branch.
        BPUncond(bp_history);
    } else {
        ++condPredicted;

        pred_taken = BPLookup(PC, bp_history);

        DPRINTF(Fetch, "BranchPred: [tid:%i]: Branch predictor predicted %i "
                "for PC %#x\n",
                tid, pred_taken, inst->readPC());
    }

    PredictorHistory predict_record(inst->seqNum, PC, pred_taken,
                                    bp_history, tid);

    // Now lookup in the BTB or RAS.
    if (pred_taken) {
        if (inst->isReturn()) {
            ++usedRAS;

            // If it's a function return call, then look up the address
            // in the RAS.
            target = RAS[tid].top();

            // Record the top entry of the RAS, and its index.
            predict_record.usedRAS = true;
            predict_record.RASIndex = RAS[tid].topIdx();
            predict_record.RASTarget = target;

            assert(predict_record.RASIndex < 16);

            RAS[tid].pop();

            DPRINTF(Fetch, "BranchPred: [tid:%i]: Instruction %#x is a return, "
                    "RAS predicted target: %#x, RAS index: %i.\n",
                    tid, inst->readPC(), target, predict_record.RASIndex);
        } else {
            ++BTBLookups;

            if (inst->isCall()) {
#if ISA_HAS_DELAY_SLOT
                Addr ras_pc = PC + (2 * sizeof(MachInst)); // Next Next PC
#else
                Addr ras_pc = PC + sizeof(MachInst); // Next PC
#endif
                RAS[tid].push(ras_pc);

                // Record that it was a call so that the top RAS entry can
                // be popped off if the speculation is incorrect.
                predict_record.wasCall = true;

                DPRINTF(Fetch, "BranchPred: [tid:%i]: Instruction %#x was a call"
                        ", adding %#x to the RAS index: %i.\n",
                        tid, inst->readPC(), ras_pc, RAS[tid].topIdx());
            }

            if (BTB.valid(PC, tid)) {
                ++BTBHits;

                // If it's not a return, use the BTB to get the target addr.
                target = BTB.lookup(PC, tid);

                DPRINTF(Fetch, "BranchPred: [tid:%i]: Instruction %#x predicted"
                        " target is %#x.\n",
                        tid, inst->readPC(), target);

            } else {
                DPRINTF(Fetch, "BranchPred: [tid:%i]: BTB doesn't have a "
                        "valid entry.\n",tid);
                pred_taken = false;
            }

        }
    }

    predHist[tid].push_front(predict_record);

    DPRINTF(Fetch, "[tid:%i]: predHist.size(): %i\n", tid, predHist[tid].size());

    return pred_taken;
}

template <class Impl>
void
BPredUnit<Impl>::update(const InstSeqNum &done_sn, unsigned tid)
{
    DPRINTF(Fetch, "BranchPred: [tid:%i]: Commiting branches until "
            "[sn:%lli].\n", tid, done_sn);

    while (!predHist[tid].empty() &&
           predHist[tid].back().seqNum <= done_sn) {
        // Update the branch predictor with the correct results.
        BPUpdate(predHist[tid].back().PC,
                 predHist[tid].back().predTaken,
                 predHist[tid].back().bpHistory);

        predHist[tid].pop_back();
    }
}

template <class Impl>
void
BPredUnit<Impl>::squash(const InstSeqNum &squashed_sn, unsigned tid)
{
    History &pred_hist = predHist[tid];

    while (!pred_hist.empty() &&
           pred_hist.front().seqNum > squashed_sn) {
        if (pred_hist.front().usedRAS) {
            DPRINTF(Fetch, "BranchPred: [tid:%i]: Restoring top of RAS to: %i,"
                    " target: %#x.\n",
                    tid,
                    pred_hist.front().RASIndex,
                    pred_hist.front().RASTarget);

            RAS[tid].restore(pred_hist.front().RASIndex,
                             pred_hist.front().RASTarget);
        } else if (pred_hist.front().wasCall) {
            DPRINTF(Fetch, "BranchPred: [tid:%i]: Removing speculative entry "
                    "added to the RAS.\n",tid);

            RAS[tid].pop();
        }

        // This call should delete the bpHistory.
        BPSquash(pred_hist.front().bpHistory);

        pred_hist.pop_front();
    }

}

template <class Impl>
void
BPredUnit<Impl>::squash(const InstSeqNum &squashed_sn,
                        const Addr &corr_target,
                        const bool actually_taken,
                        unsigned tid)
{
    // Now that we know that a branch was mispredicted, we need to undo
    // all the branches that have been seen up until this branch and
    // fix up everything.

    History &pred_hist = predHist[tid];

    ++condIncorrect;

    DPRINTF(Fetch, "BranchPred: [tid:%i]: Squashing from sequence number %i, "
            "setting target to %#x.\n",
            tid, squashed_sn, corr_target);

    squash(squashed_sn, tid);

    // If there's a squash due to a syscall, there may not be an entry
    // corresponding to the squash.  In that case, don't bother trying to
    // fix up the entry.
    if (!pred_hist.empty()) {
        assert(pred_hist.front().seqNum == squashed_sn);
        if (pred_hist.front().usedRAS) {
            ++RASIncorrect;
        }

        BPUpdate(pred_hist.front().PC, actually_taken,
                 pred_hist.front().bpHistory);

        BTB.update(pred_hist.front().PC, corr_target, tid);
        pred_hist.pop_front();
    }
}

template <class Impl>
void
BPredUnit<Impl>::BPUncond(void * &bp_history)
{
    // Only the tournament predictor cares about unconditional branches.
    if (predictor == Tournament) {
        tournamentBP->uncondBr(bp_history);
    }
}

template <class Impl>
void
BPredUnit<Impl>::BPSquash(void *bp_history)
{
    if (predictor == Local) {
        localBP->squash(bp_history);
    } else if (predictor == Tournament) {
        tournamentBP->squash(bp_history);
    } else {
        panic("Predictor type is unexpected value!");
    }
}

template <class Impl>
bool
BPredUnit<Impl>::BPLookup(Addr &inst_PC, void * &bp_history)
{
    if (predictor == Local) {
        return localBP->lookup(inst_PC, bp_history);
    } else if (predictor == Tournament) {
        return tournamentBP->lookup(inst_PC, bp_history);
    } else {
        panic("Predictor type is unexpected value!");
    }
}

template <class Impl>
void
BPredUnit<Impl>::BPUpdate(Addr &inst_PC, bool taken, void *bp_history)
{
    if (predictor == Local) {
        localBP->update(inst_PC, taken, bp_history);
    } else if (predictor == Tournament) {
        tournamentBP->update(inst_PC, taken, bp_history);
    } else {
        panic("Predictor type is unexpected value!");
    }
}

template <class Impl>
void
BPredUnit<Impl>::dump()
{
    typename History::iterator pred_hist_it;

    for (int i = 0; i < Impl::MaxThreads; ++i) {
        if (!predHist[i].empty()) {
            pred_hist_it = predHist[i].begin();

            cprintf("predHist[%i].size(): %i\n", i, predHist[i].size());

            while (pred_hist_it != predHist[i].end()) {
                cprintf("[sn:%lli], PC:%#x, tid:%i, predTaken:%i, "
                        "bpHistory:%#x\n",
                        (*pred_hist_it).seqNum, (*pred_hist_it).PC,
                        (*pred_hist_it).tid, (*pred_hist_it).predTaken,
                        (*pred_hist_it).bpHistory);
                pred_hist_it++;
            }

            cprintf("\n");
        }
    }
}
<commit_msg>Make sure the value of PC is actually updated now that the instruction target isn't set explicitly.<commit_after>/*
 * Copyright (c) 2004-2005 The Regents of The University of Michigan
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * 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;
 * neither the name of the copyright holders 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
 * OWNER 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.
 *
 * Authors: Kevin Lim
 */

#include "arch/types.hh"
#include "arch/isa_traits.hh"
#include "base/trace.hh"
#include "base/traceflags.hh"
#include "cpu/o3/bpred_unit.hh"

template<class Impl>
BPredUnit<Impl>::BPredUnit(Params *params)
  : BTB(params->BTBEntries,
        params->BTBTagSize,
        params->instShiftAmt)
{
    // Setup the selected predictor.
    if (params->predType == "local") {
        localBP = new LocalBP(params->localPredictorSize,
                              params->localCtrBits,
                              params->instShiftAmt);
        predictor = Local;
    } else if (params->predType == "tournament") {
        tournamentBP = new TournamentBP(params->localPredictorSize,
                                        params->localCtrBits,
                                        params->localHistoryTableSize,
                                        params->localHistoryBits,
                                        params->globalPredictorSize,
                                        params->globalHistoryBits,
                                        params->globalCtrBits,
                                        params->choicePredictorSize,
                                        params->choiceCtrBits,
                                        params->instShiftAmt);
        predictor = Tournament;
    } else {
        fatal("Invalid BP selected!");
    }

    for (int i=0; i < Impl::MaxThreads; i++)
        RAS[i].init(params->RASSize);
}

template <class Impl>
void
BPredUnit<Impl>::regStats()
{
    lookups
        .name(name() + ".BPredUnit.lookups")
        .desc("Number of BP lookups")
        ;

    condPredicted
        .name(name() + ".BPredUnit.condPredicted")
        .desc("Number of conditional branches predicted")
        ;

    condIncorrect
        .name(name() + ".BPredUnit.condIncorrect")
        .desc("Number of conditional branches incorrect")
        ;

    BTBLookups
        .name(name() + ".BPredUnit.BTBLookups")
        .desc("Number of BTB lookups")
        ;

    BTBHits
        .name(name() + ".BPredUnit.BTBHits")
        .desc("Number of BTB hits")
        ;

    BTBCorrect
        .name(name() + ".BPredUnit.BTBCorrect")
        .desc("Number of correct BTB predictions (this stat may not "
              "work properly.")
        ;

    usedRAS
        .name(name() + ".BPredUnit.usedRAS")
        .desc("Number of times the RAS was used to get a target.")
        ;

    RASIncorrect
        .name(name() + ".BPredUnit.RASInCorrect")
        .desc("Number of incorrect RAS predictions.")
        ;
}

template <class Impl>
void
BPredUnit<Impl>::switchOut()
{
    // Clear any state upon switch out.
    for (int i = 0; i < Impl::MaxThreads; ++i) {
        squash(0, i);
    }
}

template <class Impl>
void
BPredUnit<Impl>::takeOverFrom()
{
    // Can reset all predictor state, but it's not necessarily better
    // than leaving it be.
/*
    for (int i = 0; i < Impl::MaxThreads; ++i)
        RAS[i].reset();

    BP.reset();
    BTB.reset();
*/
}

template <class Impl>
bool
BPredUnit<Impl>::predict(DynInstPtr &inst, Addr &PC, unsigned tid)
{
    // See if branch predictor predicts taken.
    // If so, get its target addr either from the BTB or the RAS.
    // Save off record of branch stuff so the RAS can be fixed
    // up once it's done.

    using TheISA::MachInst;

    bool pred_taken = false;
    Addr target = PC;

    ++lookups;

    void *bp_history = NULL;

    if (inst->isUncondCtrl()) {
        DPRINTF(Fetch, "BranchPred: [tid:%i]: Unconditional control.\n", tid);
        pred_taken = true;
        // Tell the BP there was an unconditional branch.
        BPUncond(bp_history);
    } else {
        ++condPredicted;

        pred_taken = BPLookup(PC, bp_history);

        DPRINTF(Fetch, "BranchPred: [tid:%i]: Branch predictor predicted %i "
                "for PC %#x\n",
                tid, pred_taken, inst->readPC());
    }

    PredictorHistory predict_record(inst->seqNum, PC, pred_taken,
                                    bp_history, tid);

    // Now lookup in the BTB or RAS.
    if (pred_taken) {
        if (inst->isReturn()) {
            ++usedRAS;

            // If it's a function return call, then look up the address
            // in the RAS.
            target = RAS[tid].top();

            // Record the top entry of the RAS, and its index.
            predict_record.usedRAS = true;
            predict_record.RASIndex = RAS[tid].topIdx();
            predict_record.RASTarget = target;

            assert(predict_record.RASIndex < 16);

            RAS[tid].pop();

            DPRINTF(Fetch, "BranchPred: [tid:%i]: Instruction %#x is a return, "
                    "RAS predicted target: %#x, RAS index: %i.\n",
                    tid, inst->readPC(), target, predict_record.RASIndex);
        } else {
            ++BTBLookups;

            if (inst->isCall()) {
#if ISA_HAS_DELAY_SLOT
                Addr ras_pc = PC + (2 * sizeof(MachInst)); // Next Next PC
#else
                Addr ras_pc = PC + sizeof(MachInst); // Next PC
#endif
                RAS[tid].push(ras_pc);

                // Record that it was a call so that the top RAS entry can
                // be popped off if the speculation is incorrect.
                predict_record.wasCall = true;

                DPRINTF(Fetch, "BranchPred: [tid:%i]: Instruction %#x was a call"
                        ", adding %#x to the RAS index: %i.\n",
                        tid, inst->readPC(), ras_pc, RAS[tid].topIdx());
            }

            if (BTB.valid(PC, tid)) {
                ++BTBHits;

                // If it's not a return, use the BTB to get the target addr.
                target = BTB.lookup(PC, tid);

                DPRINTF(Fetch, "BranchPred: [tid:%i]: Instruction %#x predicted"
                        " target is %#x.\n",
                        tid, inst->readPC(), target);

            } else {
                DPRINTF(Fetch, "BranchPred: [tid:%i]: BTB doesn't have a "
                        "valid entry.\n",tid);
                pred_taken = false;
            }

        }
    }

    PC = target;

    predHist[tid].push_front(predict_record);

    DPRINTF(Fetch, "[tid:%i]: predHist.size(): %i\n", tid, predHist[tid].size());

    return pred_taken;
}

template <class Impl>
void
BPredUnit<Impl>::update(const InstSeqNum &done_sn, unsigned tid)
{
    DPRINTF(Fetch, "BranchPred: [tid:%i]: Commiting branches until "
            "[sn:%lli].\n", tid, done_sn);

    while (!predHist[tid].empty() &&
           predHist[tid].back().seqNum <= done_sn) {
        // Update the branch predictor with the correct results.
        BPUpdate(predHist[tid].back().PC,
                 predHist[tid].back().predTaken,
                 predHist[tid].back().bpHistory);

        predHist[tid].pop_back();
    }
}

template <class Impl>
void
BPredUnit<Impl>::squash(const InstSeqNum &squashed_sn, unsigned tid)
{
    History &pred_hist = predHist[tid];

    while (!pred_hist.empty() &&
           pred_hist.front().seqNum > squashed_sn) {
        if (pred_hist.front().usedRAS) {
            DPRINTF(Fetch, "BranchPred: [tid:%i]: Restoring top of RAS to: %i,"
                    " target: %#x.\n",
                    tid,
                    pred_hist.front().RASIndex,
                    pred_hist.front().RASTarget);

            RAS[tid].restore(pred_hist.front().RASIndex,
                             pred_hist.front().RASTarget);
        } else if (pred_hist.front().wasCall) {
            DPRINTF(Fetch, "BranchPred: [tid:%i]: Removing speculative entry "
                    "added to the RAS.\n",tid);

            RAS[tid].pop();
        }

        // This call should delete the bpHistory.
        BPSquash(pred_hist.front().bpHistory);

        pred_hist.pop_front();
    }

}

template <class Impl>
void
BPredUnit<Impl>::squash(const InstSeqNum &squashed_sn,
                        const Addr &corr_target,
                        const bool actually_taken,
                        unsigned tid)
{
    // Now that we know that a branch was mispredicted, we need to undo
    // all the branches that have been seen up until this branch and
    // fix up everything.

    History &pred_hist = predHist[tid];

    ++condIncorrect;

    DPRINTF(Fetch, "BranchPred: [tid:%i]: Squashing from sequence number %i, "
            "setting target to %#x.\n",
            tid, squashed_sn, corr_target);

    squash(squashed_sn, tid);

    // If there's a squash due to a syscall, there may not be an entry
    // corresponding to the squash.  In that case, don't bother trying to
    // fix up the entry.
    if (!pred_hist.empty()) {
        assert(pred_hist.front().seqNum == squashed_sn);
        if (pred_hist.front().usedRAS) {
            ++RASIncorrect;
        }

        BPUpdate(pred_hist.front().PC, actually_taken,
                 pred_hist.front().bpHistory);

        BTB.update(pred_hist.front().PC, corr_target, tid);
        pred_hist.pop_front();
    }
}

template <class Impl>
void
BPredUnit<Impl>::BPUncond(void * &bp_history)
{
    // Only the tournament predictor cares about unconditional branches.
    if (predictor == Tournament) {
        tournamentBP->uncondBr(bp_history);
    }
}

template <class Impl>
void
BPredUnit<Impl>::BPSquash(void *bp_history)
{
    if (predictor == Local) {
        localBP->squash(bp_history);
    } else if (predictor == Tournament) {
        tournamentBP->squash(bp_history);
    } else {
        panic("Predictor type is unexpected value!");
    }
}

template <class Impl>
bool
BPredUnit<Impl>::BPLookup(Addr &inst_PC, void * &bp_history)
{
    if (predictor == Local) {
        return localBP->lookup(inst_PC, bp_history);
    } else if (predictor == Tournament) {
        return tournamentBP->lookup(inst_PC, bp_history);
    } else {
        panic("Predictor type is unexpected value!");
    }
}

template <class Impl>
void
BPredUnit<Impl>::BPUpdate(Addr &inst_PC, bool taken, void *bp_history)
{
    if (predictor == Local) {
        localBP->update(inst_PC, taken, bp_history);
    } else if (predictor == Tournament) {
        tournamentBP->update(inst_PC, taken, bp_history);
    } else {
        panic("Predictor type is unexpected value!");
    }
}

template <class Impl>
void
BPredUnit<Impl>::dump()
{
    typename History::iterator pred_hist_it;

    for (int i = 0; i < Impl::MaxThreads; ++i) {
        if (!predHist[i].empty()) {
            pred_hist_it = predHist[i].begin();

            cprintf("predHist[%i].size(): %i\n", i, predHist[i].size());

            while (pred_hist_it != predHist[i].end()) {
                cprintf("[sn:%lli], PC:%#x, tid:%i, predTaken:%i, "
                        "bpHistory:%#x\n",
                        (*pred_hist_it).seqNum, (*pred_hist_it).PC,
                        (*pred_hist_it).tid, (*pred_hist_it).predTaken,
                        (*pred_hist_it).bpHistory);
                pred_hist_it++;
            }

            cprintf("\n");
        }
    }
}
<|endoftext|>