<commit_before>#ifndef AMGCL_ADAPTER_REORDER_HPP
#define AMGCL_ADAPTER_REORDER_HPP

/*
The MIT License

Copyright (c) 2012-2017 Denis Demidov <dennis.demidov@gmail.com>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

/**
\file    amgcl/adapter/reorder.hpp
\author  Denis Demidov <dennis.demidov@gmail.com>
\brief   On-the-fly reodering of matrix and vectors.
\ingroup adapters
*/

#include <boost/type_traits.hpp>
#include <boost/range/size.hpp>
#include <boost/iterator/permutation_iterator.hpp>

#include <amgcl/reorder/cuthill_mckee.hpp>
#include <amgcl/backend/builtin.hpp>
#include <amgcl/backend/detail/matrix_ops.hpp>

namespace amgcl {
namespace adapter {

template <class Matrix>
struct reordered_matrix {
    typedef typename backend::value_type<Matrix>::type value_type;
    typedef typename backend::row_iterator<Matrix>::type base_iterator;

    const Matrix &A;
    const ptrdiff_t * perm;
    const ptrdiff_t * iperm;

    reordered_matrix(const Matrix &A, const ptrdiff_t *perm, const ptrdiff_t * iperm)
        : A(A), perm(perm), iperm(iperm)
    {}

    size_t rows() const {
        return backend::rows(A);
    }

    size_t cols() const {
        return backend::cols(A);
    }

    size_t nonzeros() const {
        return backend::nonzeros(A);
    }

    struct row_iterator {
        base_iterator base;
        const ptrdiff_t * iperm;

        row_iterator(const base_iterator &base, const ptrdiff_t *iperm)
            : base(base), iperm(iperm)
        {}

        operator bool() const {
            return base;
        }

        row_iterator& operator++() {
            ++base;
            return *this;
        }

        ptrdiff_t col() const {
            return iperm[base.col()];
        }

        value_type value() const {
            return base.value();
        }
    };

    row_iterator row_begin(size_t i) const {
        return row_iterator(backend::row_begin(A, perm[i]), iperm);
    }
};

template <class Vector>
struct reordered_vector {
    typedef typename backend::value_type<typename boost::decay<Vector>::type>::type value_type;

    Vector &x;
    const ptrdiff_t *perm;

    reordered_vector(Vector &x, const ptrdiff_t *perm) : x(x), perm(perm) {}

    size_t size() const {
        return boost::size(x);
    }

    const value_type& operator[](size_t i) const {
        return x[perm[i]];
    }

    value_type& operator[](size_t i) {
        return x[perm[i]];
    }

    boost::permutation_iterator<
        typename boost::decay<Vector>::type::iterator,
        const ptrdiff_t*
        >
    begin() {
        return boost::make_permutation_iterator(boost::begin(x), perm);
    }

    boost::permutation_iterator<
        typename boost::decay<Vector>::type::const_iterator,
        const ptrdiff_t*
        >
    begin() const {
        return boost::make_permutation_iterator(boost::begin(x), perm);
    }

    boost::permutation_iterator<
        typename boost::decay<Vector>::type::iterator,
        const ptrdiff_t*
        >
    end() {
        return boost::make_permutation_iterator(boost::end(x), perm + size());
    }

    boost::permutation_iterator<
        typename boost::decay<Vector>::type::const_iterator,
        const ptrdiff_t*
        >
    end() const {
        return boost::make_permutation_iterator(boost::end(x), perm + size());
    }
};

} // namespace adapter

namespace backend {

//---------------------------------------------------------------------------
// Specialization of matrix interface
//---------------------------------------------------------------------------
template <class Matrix>
struct value_type< adapter::reordered_matrix<Matrix> >
    : value_type<Matrix>
{};

template <class Matrix>
struct rows_impl< adapter::reordered_matrix<Matrix> >
{
    static size_t get(const adapter::reordered_matrix<Matrix> &A) {
        return A.rows();
    }
};

template <class Matrix>
struct cols_impl< adapter::reordered_matrix<Matrix> >
{
    static size_t get(const adapter::reordered_matrix<Matrix> &A) {
        return A.cols();
    }
};

template <class Matrix>
struct nonzeros_impl< adapter::reordered_matrix<Matrix> >
{
    static size_t get(const adapter::reordered_matrix<Matrix> &A) {
        return A.nonzeros();
    }
};

template <class Matrix>
struct row_iterator< adapter::reordered_matrix<Matrix> >
{
    typedef
        typename adapter::reordered_matrix<Matrix>::row_iterator
        type;
};

template <class Matrix>
struct row_begin_impl< adapter::reordered_matrix<Matrix> >
{
    typedef adapter::reordered_matrix<Matrix> M;
    static typename row_iterator<M>::type
    get(const M &matrix, size_t row) {
        return matrix.row_begin(row);
    }
};

namespace detail {

template <class Matrix>
struct use_builtin_matrix_ops< adapter::reordered_matrix<Matrix> >
    : boost::true_type
{};

} // namespace detail

template <class Vector>
struct is_builtin_vector< adapter::reordered_vector<Vector> >
    : is_builtin_vector<typename boost::decay<Vector>::type>
{};

} // namespace backend

namespace adapter {

template <class ordering = reorder::cuthill_mckee<false> >
class reorder {
    public:
        template <class Matrix>
        reorder(const Matrix &A) : n(backend::rows(A)), perm(n), iperm(n)
        {
            ordering::get(A, perm);
#pragma omp parallel for
            for(ptrdiff_t i = 0; i < n; ++i) iperm[perm[i]] = i;
        }

        template <class Matrix>
        typename boost::disable_if<
            backend::is_builtin_vector<Matrix>,
            reordered_matrix<Matrix>
        >::type
        operator()(const Matrix &A) const {
            return reordered_matrix<Matrix>(A, perm.data(), iperm.data());
        }

        template <class Vector>
        typename boost::enable_if<
            backend::is_builtin_vector<Vector>,
            reordered_vector<Vector>
        >::type
        operator()(Vector &x) const {
            return reordered_vector<Vector>(x, perm.data());
        }

        template <class Vector>
        typename boost::enable_if<
            backend::is_builtin_vector<Vector>,
            reordered_vector<const Vector>
        >::type
        operator()(const Vector &x) const {
            return reordered_vector<const Vector>(x, perm.data());
        }

        template <class Vector1, class Vector2>
        void forward(const Vector1 &x, Vector2 &y) const {
#pragma omp parallel for
            for(ptrdiff_t i = 0; i < n; ++i) y[i] = x[perm[i]];
        }

        template <class Vector1, class Vector2>
        void inverse(const Vector1 &x, Vector2 &y) const {
#pragma omp parallel for
            for(ptrdiff_t i = 0; i < n; ++i) y[perm[i]] = x[i];
        }

    private:
        ptrdiff_t n;
        backend::numa_vector<ptrdiff_t> perm, iperm;
};

} // namespace adapter
} // namespace amgcl

#endif
<commit_msg>Resolve an ambiguity<commit_after>#ifndef AMGCL_ADAPTER_REORDER_HPP
#define AMGCL_ADAPTER_REORDER_HPP

/*
The MIT License

Copyright (c) 2012-2017 Denis Demidov <dennis.demidov@gmail.com>

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

/**
\file    amgcl/adapter/reorder.hpp
\author  Denis Demidov <dennis.demidov@gmail.com>
\brief   On-the-fly reodering of matrix and vectors.
\ingroup adapters
*/

#include <boost/type_traits.hpp>
#include <boost/range/size.hpp>
#include <boost/iterator/permutation_iterator.hpp>

#include <amgcl/reorder/cuthill_mckee.hpp>
#include <amgcl/backend/builtin.hpp>
#include <amgcl/backend/detail/matrix_ops.hpp>

namespace amgcl {
namespace adapter {

template <class Matrix>
struct reordered_matrix {
    typedef typename backend::value_type<Matrix>::type value_type;
    typedef typename backend::row_iterator<Matrix>::type base_iterator;

    const Matrix &A;
    const ptrdiff_t * perm;
    const ptrdiff_t * iperm;

    reordered_matrix(const Matrix &A, const ptrdiff_t *perm, const ptrdiff_t * iperm)
        : A(A), perm(perm), iperm(iperm)
    {}

    size_t rows() const {
        return backend::rows(A);
    }

    size_t cols() const {
        return backend::cols(A);
    }

    size_t nonzeros() const {
        return backend::nonzeros(A);
    }

    struct row_iterator {
        base_iterator base;
        const ptrdiff_t * iperm;

        row_iterator(const base_iterator &base, const ptrdiff_t *iperm)
            : base(base), iperm(iperm)
        {}

        operator bool() const {
            return base;
        }

        row_iterator& operator++() {
            ++base;
            return *this;
        }

        ptrdiff_t col() const {
            return iperm[base.col()];
        }

        value_type value() const {
            return base.value();
        }
    };

    row_iterator row_begin(size_t i) const {
        return row_iterator(backend::row_begin(A, perm[i]), iperm);
    }
};

template <class Vector>
struct reordered_vector {
    typedef typename backend::value_type<typename boost::decay<Vector>::type>::type value_type;

    Vector &x;
    const ptrdiff_t *perm;

    reordered_vector(Vector &x, const ptrdiff_t *perm) : x(x), perm(perm) {}

    size_t size() const {
        return boost::size(x);
    }

    const value_type& operator[](size_t i) const {
        return x[perm[i]];
    }

    value_type& operator[](size_t i) {
        return x[perm[i]];
    }

    boost::permutation_iterator<
        typename boost::decay<Vector>::type::iterator,
        const ptrdiff_t*
        >
    begin() {
        return boost::make_permutation_iterator(boost::begin(x), perm);
    }

    boost::permutation_iterator<
        typename boost::decay<Vector>::type::const_iterator,
        const ptrdiff_t*
        >
    begin() const {
        return boost::make_permutation_iterator(boost::begin(x), perm);
    }

    boost::permutation_iterator<
        typename boost::decay<Vector>::type::iterator,
        const ptrdiff_t*
        >
    end() {
        return boost::make_permutation_iterator(boost::end(x), perm + size());
    }

    boost::permutation_iterator<
        typename boost::decay<Vector>::type::const_iterator,
        const ptrdiff_t*
        >
    end() const {
        return boost::make_permutation_iterator(boost::end(x), perm + size());
    }
};

} // namespace adapter

namespace backend {

//---------------------------------------------------------------------------
// Specialization of matrix interface
//---------------------------------------------------------------------------
template <class Matrix>
struct value_type< adapter::reordered_matrix<Matrix> >
    : value_type<Matrix>
{};

template <class Matrix>
struct rows_impl< adapter::reordered_matrix<Matrix> >
{
    static size_t get(const adapter::reordered_matrix<Matrix> &A) {
        return A.rows();
    }
};

template <class Matrix>
struct cols_impl< adapter::reordered_matrix<Matrix> >
{
    static size_t get(const adapter::reordered_matrix<Matrix> &A) {
        return A.cols();
    }
};

template <class Matrix>
struct nonzeros_impl< adapter::reordered_matrix<Matrix> >
{
    static size_t get(const adapter::reordered_matrix<Matrix> &A) {
        return A.nonzeros();
    }
};

template <class Matrix>
struct row_iterator< adapter::reordered_matrix<Matrix> >
{
    typedef
        typename adapter::reordered_matrix<Matrix>::row_iterator
        type;
};

template <class Matrix>
struct row_begin_impl< adapter::reordered_matrix<Matrix> >
{
    typedef adapter::reordered_matrix<Matrix> M;
    static typename row_iterator<M>::type
    get(const M &matrix, size_t row) {
        return matrix.row_begin(row);
    }
};

namespace detail {

template <class Matrix>
struct use_builtin_matrix_ops< adapter::reordered_matrix<Matrix> >
    : boost::true_type
{};

} // namespace detail

template <class Vector>
struct is_builtin_vector< adapter::reordered_vector<Vector> >
    : is_builtin_vector<typename boost::decay<Vector>::type>
{};

} // namespace backend

namespace adapter {

template <class ordering = amgcl::reorder::cuthill_mckee<false> >
class reorder {
    public:
        template <class Matrix>
        reorder(const Matrix &A) : n(backend::rows(A)), perm(n), iperm(n)
        {
            ordering::get(A, perm);
#pragma omp parallel for
            for(ptrdiff_t i = 0; i < n; ++i) iperm[perm[i]] = i;
        }

        template <class Matrix>
        typename boost::disable_if<
            backend::is_builtin_vector<Matrix>,
            reordered_matrix<Matrix>
        >::type
        operator()(const Matrix &A) const {
            return reordered_matrix<Matrix>(A, perm.data(), iperm.data());
        }

        template <class Vector>
        typename boost::enable_if<
            backend::is_builtin_vector<Vector>,
            reordered_vector<Vector>
        >::type
        operator()(Vector &x) const {
            return reordered_vector<Vector>(x, perm.data());
        }

        template <class Vector>
        typename boost::enable_if<
            backend::is_builtin_vector<Vector>,
            reordered_vector<const Vector>
        >::type
        operator()(const Vector &x) const {
            return reordered_vector<const Vector>(x, perm.data());
        }

        template <class Vector1, class Vector2>
        void forward(const Vector1 &x, Vector2 &y) const {
#pragma omp parallel for
            for(ptrdiff_t i = 0; i < n; ++i) y[i] = x[perm[i]];
        }

        template <class Vector1, class Vector2>
        void inverse(const Vector1 &x, Vector2 &y) const {
#pragma omp parallel for
            for(ptrdiff_t i = 0; i < n; ++i) y[perm[i]] = x[i];
        }

    private:
        ptrdiff_t n;
        backend::numa_vector<ptrdiff_t> perm, iperm;
};

} // namespace adapter
} // namespace amgcl

#endif
<|endoftext|>


<commit_before>//===- lib/Linker/LinkArchives.cpp - Link LLVM objects and libraries ------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains routines to handle linking together LLVM bytecode files,
// and to handle annoying things like static libraries.
//
//===----------------------------------------------------------------------===//

#include "llvm/Linker.h"
#include "llvm/Module.h"
#include "llvm/ModuleProvider.h"
#include "llvm/ADT/SetOperations.h"
#include "llvm/Bytecode/Reader.h"
#include "llvm/Bytecode/Archive.h"
#include "llvm/Config/config.h"
#include <memory>
#include <set>
#include <iostream>

using namespace llvm;

/// GetAllDefinedSymbols - Modifies its parameter DefinedSymbols to contain the
/// name of each externally-visible symbol defined in M.
///
static void
GetAllDefinedSymbols(Module *M, std::set<std::string> &DefinedSymbols) {
  for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I)
    if (I->hasName() && !I->isExternal() && !I->hasInternalLinkage())
      DefinedSymbols.insert(I->getName());
  for (Module::giterator I = M->gbegin(), E = M->gend(); I != E; ++I)
    if (I->hasName() && !I->isExternal() && !I->hasInternalLinkage())
      DefinedSymbols.insert(I->getName());
}

/// GetAllUndefinedSymbols - calculates the set of undefined symbols that still
/// exist in an LLVM module. This is a bit tricky because there may be two
/// symbols with the same name but different LLVM types that will be resolved to
/// each other but aren't currently (thus we need to treat it as resolved).
///
/// Inputs:
///  M - The module in which to find undefined symbols.
///
/// Outputs:
///  UndefinedSymbols - A set of C++ strings containing the name of all
///                     undefined symbols.
///
static void
GetAllUndefinedSymbols(Module *M, std::set<std::string> &UndefinedSymbols) {
  std::set<std::string> DefinedSymbols;
  UndefinedSymbols.clear();

  for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I)
    if (I->hasName()) {
      if (I->isExternal())
        UndefinedSymbols.insert(I->getName());
      else if (!I->hasInternalLinkage())
        DefinedSymbols.insert(I->getName());
    }
  for (Module::giterator I = M->gbegin(), E = M->gend(); I != E; ++I)
    if (I->hasName()) {
      if (I->isExternal())
        UndefinedSymbols.insert(I->getName());
      else if (!I->hasInternalLinkage())
        DefinedSymbols.insert(I->getName());
    }

  // Prune out any defined symbols from the undefined symbols set...
  for (std::set<std::string>::iterator I = UndefinedSymbols.begin();
       I != UndefinedSymbols.end(); )
    if (DefinedSymbols.count(*I))
      UndefinedSymbols.erase(I++);  // This symbol really is defined!
    else
      ++I; // Keep this symbol in the undefined symbols list
}

/// LinkInArchive - opens an archive library and link in all objects which
/// provide symbols that are currently undefined.
///
/// Inputs:
///  Filename - The pathname of the archive.
///
/// Return Value:
///  TRUE  - An error occurred.
///  FALSE - No errors.
bool
Linker::LinkInArchive(const sys::Path &Filename) {

  // Make sure this is an archive file we're dealing with
  if (!Filename.isArchive())
    return error("File '" + Filename.toString() + "' is not an archive.");

  // Open the archive file
  verbose("Linking archive file '" + Filename.toString() + "'");

  // Find all of the symbols currently undefined in the bytecode program.
  // If all the symbols are defined, the program is complete, and there is
  // no reason to link in any archive files.
  std::set<std::string> UndefinedSymbols;
  GetAllUndefinedSymbols(Composite, UndefinedSymbols);

  if (UndefinedSymbols.empty()) {
    verbose("No symbols undefined, skipping library '" +
            Filename.toString() + "'");
    return false;  // No need to link anything in!
  }

  std::string ErrMsg;
  std::auto_ptr<Archive> AutoArch (
    Archive::OpenAndLoadSymbols(Filename,&ErrMsg));

  Archive* arch = AutoArch.get();

  if (!arch)
    return error("Cannot read archive '" + Filename.toString() +
                 "': " + ErrMsg);

  // Save a set of symbols that are not defined by the archive. Since we're
  // entering a loop, there's no point searching for these multiple times. This
  // variable is used to "set_subtract" from the set of undefined symbols.
  std::set<std::string> NotDefinedByArchive;

  // While we are linking in object files, loop.
  while (true) {

    // Find the modules we need to link into the target module
    std::set<ModuleProvider*> Modules;
    arch->findModulesDefiningSymbols(UndefinedSymbols, Modules);

    // If we didn't find any more modules to link this time, we are done
    // searching this archive.
    if (Modules.empty())
      break;

    // Any symbols remaining in UndefinedSymbols after
    // findModulesDefiningSymbols are ones that the archive does not define. So
    // we add them to the NotDefinedByArchive variable now.
    NotDefinedByArchive.insert(UndefinedSymbols.begin(),
        UndefinedSymbols.end());

    // Loop over all the ModuleProviders that we got back from the archive
    for (std::set<ModuleProvider*>::iterator I=Modules.begin(), E=Modules.end();
         I != E; ++I) {

      // Get the module we must link in.
      std::auto_ptr<Module> AutoModule( (*I)->releaseModule() );
      Module* aModule = AutoModule.get();

      verbose("  Linking in module: " + aModule->getModuleIdentifier());

      // Link it in
      if (this->LinkInModule(aModule))
        return error("Cannot link in module '" +
                     aModule->getModuleIdentifier() + "': " + Error);
    }

    // Get the undefined symbols from the aggregate module. This recomputes the
    // symbols we still need after the new modules have been linked in.
    GetAllUndefinedSymbols(Composite, UndefinedSymbols);

    // At this point we have two sets of undefined symbols: UndefinedSymbols
    // which holds the undefined symbols from all the modules, and
    // NotDefinedByArchive which holds symbols we know the archive doesn't
    // define. There's no point searching for symbols that we won't find in the
    // archive so we subtract these sets.
    set_subtract<std::set<std::string>,std::set<std::string> >(
        UndefinedSymbols,NotDefinedByArchive);

    // If there's no symbols left, no point in continuing to search the
    // archive.
    if (UndefinedSymbols.empty())
      break;
  }

  return false;
}
<commit_msg>Minor cleanup.  No need to explicitly tell the compiler the template arguments.<commit_after>//===- lib/Linker/LinkArchives.cpp - Link LLVM objects and libraries ------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains routines to handle linking together LLVM bytecode files,
// and to handle annoying things like static libraries.
//
//===----------------------------------------------------------------------===//

#include "llvm/Linker.h"
#include "llvm/Module.h"
#include "llvm/ModuleProvider.h"
#include "llvm/ADT/SetOperations.h"
#include "llvm/Bytecode/Reader.h"
#include "llvm/Bytecode/Archive.h"
#include "llvm/Config/config.h"
#include <memory>
#include <set>
#include <iostream>

using namespace llvm;

/// GetAllDefinedSymbols - Modifies its parameter DefinedSymbols to contain the
/// name of each externally-visible symbol defined in M.
///
static void
GetAllDefinedSymbols(Module *M, std::set<std::string> &DefinedSymbols) {
  for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I)
    if (I->hasName() && !I->isExternal() && !I->hasInternalLinkage())
      DefinedSymbols.insert(I->getName());
  for (Module::giterator I = M->gbegin(), E = M->gend(); I != E; ++I)
    if (I->hasName() && !I->isExternal() && !I->hasInternalLinkage())
      DefinedSymbols.insert(I->getName());
}

/// GetAllUndefinedSymbols - calculates the set of undefined symbols that still
/// exist in an LLVM module. This is a bit tricky because there may be two
/// symbols with the same name but different LLVM types that will be resolved to
/// each other but aren't currently (thus we need to treat it as resolved).
///
/// Inputs:
///  M - The module in which to find undefined symbols.
///
/// Outputs:
///  UndefinedSymbols - A set of C++ strings containing the name of all
///                     undefined symbols.
///
static void
GetAllUndefinedSymbols(Module *M, std::set<std::string> &UndefinedSymbols) {
  std::set<std::string> DefinedSymbols;
  UndefinedSymbols.clear();

  for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I)
    if (I->hasName()) {
      if (I->isExternal())
        UndefinedSymbols.insert(I->getName());
      else if (!I->hasInternalLinkage())
        DefinedSymbols.insert(I->getName());
    }
  for (Module::giterator I = M->gbegin(), E = M->gend(); I != E; ++I)
    if (I->hasName()) {
      if (I->isExternal())
        UndefinedSymbols.insert(I->getName());
      else if (!I->hasInternalLinkage())
        DefinedSymbols.insert(I->getName());
    }

  // Prune out any defined symbols from the undefined symbols set...
  for (std::set<std::string>::iterator I = UndefinedSymbols.begin();
       I != UndefinedSymbols.end(); )
    if (DefinedSymbols.count(*I))
      UndefinedSymbols.erase(I++);  // This symbol really is defined!
    else
      ++I; // Keep this symbol in the undefined symbols list
}

/// LinkInArchive - opens an archive library and link in all objects which
/// provide symbols that are currently undefined.
///
/// Inputs:
///  Filename - The pathname of the archive.
///
/// Return Value:
///  TRUE  - An error occurred.
///  FALSE - No errors.
bool
Linker::LinkInArchive(const sys::Path &Filename) {

  // Make sure this is an archive file we're dealing with
  if (!Filename.isArchive())
    return error("File '" + Filename.toString() + "' is not an archive.");

  // Open the archive file
  verbose("Linking archive file '" + Filename.toString() + "'");

  // Find all of the symbols currently undefined in the bytecode program.
  // If all the symbols are defined, the program is complete, and there is
  // no reason to link in any archive files.
  std::set<std::string> UndefinedSymbols;
  GetAllUndefinedSymbols(Composite, UndefinedSymbols);

  if (UndefinedSymbols.empty()) {
    verbose("No symbols undefined, skipping library '" +
            Filename.toString() + "'");
    return false;  // No need to link anything in!
  }

  std::string ErrMsg;
  std::auto_ptr<Archive> AutoArch (
    Archive::OpenAndLoadSymbols(Filename,&ErrMsg));

  Archive* arch = AutoArch.get();

  if (!arch)
    return error("Cannot read archive '" + Filename.toString() +
                 "': " + ErrMsg);

  // Save a set of symbols that are not defined by the archive. Since we're
  // entering a loop, there's no point searching for these multiple times. This
  // variable is used to "set_subtract" from the set of undefined symbols.
  std::set<std::string> NotDefinedByArchive;

  // While we are linking in object files, loop.
  while (true) {

    // Find the modules we need to link into the target module
    std::set<ModuleProvider*> Modules;
    arch->findModulesDefiningSymbols(UndefinedSymbols, Modules);

    // If we didn't find any more modules to link this time, we are done
    // searching this archive.
    if (Modules.empty())
      break;

    // Any symbols remaining in UndefinedSymbols after
    // findModulesDefiningSymbols are ones that the archive does not define. So
    // we add them to the NotDefinedByArchive variable now.
    NotDefinedByArchive.insert(UndefinedSymbols.begin(),
        UndefinedSymbols.end());

    // Loop over all the ModuleProviders that we got back from the archive
    for (std::set<ModuleProvider*>::iterator I=Modules.begin(), E=Modules.end();
         I != E; ++I) {

      // Get the module we must link in.
      std::auto_ptr<Module> AutoModule( (*I)->releaseModule() );
      Module* aModule = AutoModule.get();

      verbose("  Linking in module: " + aModule->getModuleIdentifier());

      // Link it in
      if (LinkInModule(aModule))
        return error("Cannot link in module '" +
                     aModule->getModuleIdentifier() + "': " + Error);
    }

    // Get the undefined symbols from the aggregate module. This recomputes the
    // symbols we still need after the new modules have been linked in.
    GetAllUndefinedSymbols(Composite, UndefinedSymbols);

    // At this point we have two sets of undefined symbols: UndefinedSymbols
    // which holds the undefined symbols from all the modules, and
    // NotDefinedByArchive which holds symbols we know the archive doesn't
    // define. There's no point searching for symbols that we won't find in the
    // archive so we subtract these sets.
    set_subtract(UndefinedSymbols, NotDefinedByArchive);

    // If there's no symbols left, no point in continuing to search the
    // archive.
    if (UndefinedSymbols.empty())
      break;
  }

  return false;
}
<|endoftext|>


<commit_before>#include <QtCore/QCoreApplication>
#include <QtCore/QEvent>
#include <QtCore/QSocketNotifier>
#include <sys/epoll.h>
#include <errno.h>
#include "eventdispatcher_epoll_p.h"
#include "qt4compat.h"

void EventDispatcherEPollPrivate::registerSocketNotifier(QSocketNotifier* notifier)
{
	int events = 0;
	QSocketNotifier** n = 0;
	int fd = static_cast<int>(notifier->socket());

	epoll_event e;
	e.data.fd = fd;

	HandleData* data;
	HandleHash::Iterator it = this->m_handles.find(fd);

	if (it == this->m_handles.end()) {
		data        = new EventDispatcherEPollPrivate::HandleData();
		data->type  = EventDispatcherEPollPrivate::htSocketNotifier;
		data->sni.r = 0;
		data->sni.w = 0;
		data->sni.x = 0;

		switch (notifier->type()) {
			case QSocketNotifier::Read:      events = EPOLLIN;  n = &data->sni.r; break;
			case QSocketNotifier::Write:     events = EPOLLOUT; n = &data->sni.w; break;
			case QSocketNotifier::Exception: events = EPOLLPRI; n = &data->sni.x; break;
			default:
				Q_UNREACHABLE();
		}

		data->sni.events = events;
		e.events         = events;
		*n               = notifier;

		int res = epoll_ctl(this->m_epoll_fd, EPOLL_CTL_ADD, fd, &e);
		if (Q_UNLIKELY(res != 0)) {
			qErrnoWarning("%s: epoll_ctl() failed", Q_FUNC_INFO);
			delete data;
			return;
		}

		this->m_handles.insert(fd, data);
	}
	else {
		data = it.value();

		Q_ASSERT(data->type == EventDispatcherEPollPrivate::htSocketNotifier);
		if (data->type == EventDispatcherEPollPrivate::htSocketNotifier) {
			switch (notifier->type()) {
				case QSocketNotifier::Read:      events = EPOLLIN;  n = &data->sni.r; break;
				case QSocketNotifier::Write:     events = EPOLLOUT; n = &data->sni.w; break;
				case QSocketNotifier::Exception: events = EPOLLPRI; n = &data->sni.x; break;
				default:
					Q_UNREACHABLE();
			}

			Q_ASSERT(n != 0);
			if (Q_UNLIKELY(*n != 0)) {
				qWarning("%s: cannot add two socket notifiers of the same type for the same descriptor", Q_FUNC_INFO);
				return;
			}

			data->sni.events |= events;
			e.events          = data->sni.events;
			*n                = notifier;

			int res = epoll_ctl(this->m_epoll_fd, EPOLL_CTL_MOD, fd, &e);
			if (Q_UNLIKELY(res != 0)) {
				qErrnoWarning("%s: epoll_ctl() failed", Q_FUNC_INFO);
				return;
			}
		}
		else {
			Q_UNREACHABLE();
		}
	}

	this->m_notifiers.insert(notifier, data);
}

void EventDispatcherEPollPrivate::unregisterSocketNotifier(QSocketNotifier* notifier)
{
	SocketNotifierHash::Iterator it = this->m_notifiers.find(notifier);
	if (Q_LIKELY(it != this->m_notifiers.end())) {
		HandleData* info = it.value();
		int fd           = static_cast<int>(notifier->socket());

		this->m_notifiers.erase(it); // Hash is not rehashed

		HandleHash::Iterator hi = this->m_handles.find(fd);
		Q_ASSERT(hi != this->m_handles.end());

		struct epoll_event e;
		e.data.fd = fd;

		if (info->sni.r == notifier) {
			info->sni.events &= ~EPOLLIN;
			info->sni.r       = 0;
		}
		else if (info->sni.w == notifier) {
			info->sni.events &= ~EPOLLOUT;
			info->sni.w       = 0;
		}
		else if (info->sni.x == notifier) {
			info->sni.events &= ~EPOLLPRI;
			info->sni.x       = 0;
		}
		else {
			qCritical("%s: cannot find socket notifier %p", Q_FUNC_INFO, notifier);
		}

		e.events = info->sni.events;

		int res;

		if (info->sni.r || info->sni.w || info->sni.x) {
			res = epoll_ctl(this->m_epoll_fd, EPOLL_CTL_MOD, fd, &e);
		}
		else {
			res = epoll_ctl(this->m_epoll_fd, EPOLL_CTL_DEL, fd, &e);
			if (Q_UNLIKELY(res != 0 && EBADF == errno)) {
				res = 0;
			}

			this->m_handles.erase(hi);
			delete info;
		}

		if (Q_UNLIKELY(res != 0)) {
			qErrnoWarning("%s: epoll_ctl() failed", Q_FUNC_INFO);
		}
	}
}

void EventDispatcherEPollPrivate::socket_notifier_callback(SocketNotifierInfo *n, int events)
{
	QEvent e(QEvent::SockAct);

	if (n->r && (events & EPOLLIN)) {
		QCoreApplication::sendEvent(n->r, &e);
	}

	if (n->w && (events & EPOLLOUT)) {
		QCoreApplication::sendEvent(n->w, &e);
	}

	if (n->x && (events & EPOLLPRI)) {
		QCoreApplication::sendEvent(n->x, &e);
	}
}

void EventDispatcherEPollPrivate::disableSocketNotifiers(bool disable)
{
	epoll_event e;

	SocketNotifierHash::ConstIterator it = this->m_notifiers.constBegin();
	while (it != this->m_notifiers.constEnd()) {
		QSocketNotifier* notifier = it.key();
		HandleData* info          = it.value();
		int fd                    = static_cast<int>(notifier->socket());

		e.events  = disable ? 0 : info->sni.events;
		e.data.fd = fd;
		int res = epoll_ctl(this->m_epoll_fd, EPOLL_CTL_MOD, fd, &e);
		if (Q_UNLIKELY(res != 0)) {
			qErrnoWarning("%s: epoll_ctl() failed", Q_FUNC_INFO);
		}

		++it;
	}
}
<commit_msg>Fix for Issue #3<commit_after>#include <QtCore/QCoreApplication>
#include <QtCore/QEvent>
#include <QtCore/QPointer>
#include <QtCore/QSocketNotifier>
#include <sys/epoll.h>
#include <errno.h>
#include "eventdispatcher_epoll_p.h"
#include "qt4compat.h"

void EventDispatcherEPollPrivate::registerSocketNotifier(QSocketNotifier* notifier)
{
	int events = 0;
	QSocketNotifier** n = 0;
	int fd = static_cast<int>(notifier->socket());

	epoll_event e;
	e.data.fd = fd;

	HandleData* data;
	HandleHash::Iterator it = this->m_handles.find(fd);

	if (it == this->m_handles.end()) {
		data        = new EventDispatcherEPollPrivate::HandleData();
		data->type  = EventDispatcherEPollPrivate::htSocketNotifier;
		data->sni.r = 0;
		data->sni.w = 0;
		data->sni.x = 0;

		switch (notifier->type()) {
			case QSocketNotifier::Read:      events = EPOLLIN;  n = &data->sni.r; break;
			case QSocketNotifier::Write:     events = EPOLLOUT; n = &data->sni.w; break;
			case QSocketNotifier::Exception: events = EPOLLPRI; n = &data->sni.x; break;
			default:
				Q_UNREACHABLE();
		}

		data->sni.events = events;
		e.events         = events;
		*n               = notifier;

		int res = epoll_ctl(this->m_epoll_fd, EPOLL_CTL_ADD, fd, &e);
		if (Q_UNLIKELY(res != 0)) {
			qErrnoWarning("%s: epoll_ctl() failed", Q_FUNC_INFO);
			delete data;
			return;
		}

		this->m_handles.insert(fd, data);
	}
	else {
		data = it.value();

		Q_ASSERT(data->type == EventDispatcherEPollPrivate::htSocketNotifier);
		if (data->type == EventDispatcherEPollPrivate::htSocketNotifier) {
			switch (notifier->type()) {
				case QSocketNotifier::Read:      events = EPOLLIN;  n = &data->sni.r; break;
				case QSocketNotifier::Write:     events = EPOLLOUT; n = &data->sni.w; break;
				case QSocketNotifier::Exception: events = EPOLLPRI; n = &data->sni.x; break;
				default:
					Q_UNREACHABLE();
			}

			Q_ASSERT(n != 0);
			if (Q_UNLIKELY(*n != 0)) {
				qWarning("%s: cannot add two socket notifiers of the same type for the same descriptor", Q_FUNC_INFO);
				return;
			}

			data->sni.events |= events;
			e.events          = data->sni.events;
			*n                = notifier;

			int res = epoll_ctl(this->m_epoll_fd, EPOLL_CTL_MOD, fd, &e);
			if (Q_UNLIKELY(res != 0)) {
				qErrnoWarning("%s: epoll_ctl() failed", Q_FUNC_INFO);
				return;
			}
		}
		else {
			Q_UNREACHABLE();
		}
	}

	this->m_notifiers.insert(notifier, data);
}

void EventDispatcherEPollPrivate::unregisterSocketNotifier(QSocketNotifier* notifier)
{
	SocketNotifierHash::Iterator it = this->m_notifiers.find(notifier);
	if (Q_LIKELY(it != this->m_notifiers.end())) {
		HandleData* info = it.value();
		int fd           = static_cast<int>(notifier->socket());

		this->m_notifiers.erase(it); // Hash is not rehashed

		HandleHash::Iterator hi = this->m_handles.find(fd);
		Q_ASSERT(hi != this->m_handles.end());

		struct epoll_event e;
		e.data.fd = fd;

		if (info->sni.r == notifier) {
			info->sni.events &= ~EPOLLIN;
			info->sni.r       = 0;
		}
		else if (info->sni.w == notifier) {
			info->sni.events &= ~EPOLLOUT;
			info->sni.w       = 0;
		}
		else if (info->sni.x == notifier) {
			info->sni.events &= ~EPOLLPRI;
			info->sni.x       = 0;
		}
		else {
			qCritical("%s: cannot find socket notifier %p", Q_FUNC_INFO, notifier);
		}

		e.events = info->sni.events;

		int res;

		if (info->sni.r || info->sni.w || info->sni.x) {
			res = epoll_ctl(this->m_epoll_fd, EPOLL_CTL_MOD, fd, &e);
		}
		else {
			res = epoll_ctl(this->m_epoll_fd, EPOLL_CTL_DEL, fd, &e);
			if (Q_UNLIKELY(res != 0 && EBADF == errno)) {
				res = 0;
			}

			this->m_handles.erase(hi);
			delete info;
		}

		if (Q_UNLIKELY(res != 0)) {
			qErrnoWarning("%s: epoll_ctl() failed", Q_FUNC_INFO);
		}
	}
}

void EventDispatcherEPollPrivate::socket_notifier_callback(SocketNotifierInfo* n, int events)
{
	Q_ASSERT(n != 0);
	QEvent e(QEvent::SockAct);

	QPointer<QSocketNotifier> r(n->r);
	QPointer<QSocketNotifier> w(n->w);
	QPointer<QSocketNotifier> x(n->x);

	if (r && (events & EPOLLIN)) {
		QCoreApplication::sendEvent(r, &e);
	}

	if (w && (events & EPOLLOUT)) {
		QCoreApplication::sendEvent(w, &e);
	}

	if (x && (events & EPOLLPRI)) {
		QCoreApplication::sendEvent(x, &e);
	}
}

void EventDispatcherEPollPrivate::disableSocketNotifiers(bool disable)
{
	epoll_event e;

	SocketNotifierHash::ConstIterator it = this->m_notifiers.constBegin();
	while (it != this->m_notifiers.constEnd()) {
		QSocketNotifier* notifier = it.key();
		HandleData* info          = it.value();
		int fd                    = static_cast<int>(notifier->socket());

		e.events  = disable ? 0 : info->sni.events;
		e.data.fd = fd;
		int res = epoll_ctl(this->m_epoll_fd, EPOLL_CTL_MOD, fd, &e);
		if (Q_UNLIKELY(res != 0)) {
			qErrnoWarning("%s: epoll_ctl() failed", Q_FUNC_INFO);
		}

		++it;
	}
}
<|endoftext|>


<commit_before>/**
* Server Key Exchange Message
* (C) 2004-2010 Jack Lloyd
*
* Released under the terms of the Botan license
*/

#include <botan/tls_messages.h>
#include <botan/pubkey.h>
#include <botan/dh.h>
#include <botan/rsa.h>
#include <botan/dsa.h>
#include <botan/loadstor.h>
#include <memory>

namespace Botan {

/**
* Create a new Server Key Exchange message
*/
Server_Key_Exchange::Server_Key_Exchange(RandomNumberGenerator& rng,
                                         Record_Writer& writer,
                                         const Public_Key* kex_key,
                                         const Private_Key* priv_key,
                                         const MemoryRegion<byte>& c_random,
                                         const MemoryRegion<byte>& s_random,
                                         HandshakeHash& hash)
   {
   const DH_PublicKey* dh_pub = dynamic_cast<const DH_PublicKey*>(kex_key);
   const RSA_PublicKey* rsa_pub = dynamic_cast<const RSA_PublicKey*>(kex_key);

   if(dh_pub)
      {
      params.push_back(dh_pub->get_domain().get_p());
      params.push_back(dh_pub->get_domain().get_g());
      params.push_back(BigInt::decode(dh_pub->public_value()));
      }
   else if(rsa_pub)
      {
      params.push_back(rsa_pub->get_n());
      params.push_back(rsa_pub->get_e());
      }
   else
      throw Invalid_Argument("Bad key for TLS key exchange: not DH or RSA");

   std::string padding = "";
   Signature_Format format = IEEE_1363;

   if(priv_key->algo_name() == "RSA")
      padding = "EMSA3(TLS.Digest.0)";
   else if(priv_key->algo_name() == "DSA")
      {
      padding == "EMSA1(SHA-1)";
      format = DER_SEQUENCE;
      }
   else
      throw Invalid_Argument(priv_key->algo_name() +
                             " is invalid/unknown for TLS signatures");

   PK_Signer signer(*priv_key, padding, format);

   signer.update(c_random);
   signer.update(s_random);
   signer.update(serialize_params());
   signature = signer.signature(rng);

   send(writer, hash);
   }

/**
* Serialize a Server Key Exchange message
*/
SecureVector<byte> Server_Key_Exchange::serialize() const
   {
   SecureVector<byte> buf = serialize_params();
   u16bit sig_len = signature.size();
   buf.append(get_byte(0, sig_len));
   buf.append(get_byte(1, sig_len));
   buf.append(signature);
   return buf;
   }

/**
* Serialize the ServerParams structure
*/
SecureVector<byte> Server_Key_Exchange::serialize_params() const
   {
   SecureVector<byte> buf;
   for(u32bit j = 0; j != params.size(); j++)
      {
      SecureVector<byte> param = BigInt::encode(params[j]);
      u16bit param_size = param.size();

      buf.append(get_byte(0, param_size));
      buf.append(get_byte(1, param_size));
      buf.append(param);
      }
   return buf;
   }

/**
* Deserialize a Server Key Exchange message
*/
void Server_Key_Exchange::deserialize(const MemoryRegion<byte>& buf)
   {
   if(buf.size() < 6)
      throw Decoding_Error("Server_Key_Exchange: Packet corrupted");

   SecureVector<byte> values[4];
   u32bit so_far = 0;

   for(u32bit j = 0; j != 4; j++)
      {
      u16bit len = make_u16bit(buf[so_far], buf[so_far+1]);
      so_far += 2;

      if(len + so_far > buf.size())
         throw Decoding_Error("Server_Key_Exchange: Packet corrupted");

      values[j].set(buf + so_far, len);
      so_far += len;

      if(j == 2 && so_far == buf.size())
         break;
      }

   params.push_back(BigInt::decode(values[0]));
   params.push_back(BigInt::decode(values[1]));
   if(values[3].size())
      {
      params.push_back(BigInt::decode(values[2]));
      signature = values[3];
      }
   else
      signature = values[2];
   }

/**
* Return the public key
*/
Public_Key* Server_Key_Exchange::key() const
   {
   if(params.size() == 2)
      return new RSA_PublicKey(params[0], params[1]);
   else if(params.size() == 3)
      return new DH_PublicKey(DL_Group(params[0], params[1]), params[2]);
   else
      throw Internal_Error("Server_Key_Exchange::key: No key set");
   }

/**
* Verify a Server Key Exchange message
*/
bool Server_Key_Exchange::verify(const X509_Certificate& cert,
                                 const MemoryRegion<byte>& c_random,
                                 const MemoryRegion<byte>& s_random) const
   {

   std::auto_ptr<Public_Key> key(cert.subject_public_key());

   std::string padding = "";
   Signature_Format format = IEEE_1363;

   if(key->algo_name() == "RSA")
      padding = "EMSA3(TLS.Digest.0)";
   else if(key->algo_name() == "DSA")
      {
      padding == "EMSA1(SHA-1)";
      format = DER_SEQUENCE;
      }
   else
      throw Invalid_Argument(key->algo_name() +
                             " is invalid/unknown for TLS signatures");

   PK_Verifier verifier(*key, padding, format);

   SecureVector<byte> params_got = serialize_params();
   verifier.update(c_random);
   verifier.update(s_random);
   verifier.update(params_got);

   return verifier.check_signature(signature, signature.size());
   }

}
<commit_msg>Fix DSA TLS servers<commit_after>/**
* Server Key Exchange Message
* (C) 2004-2010 Jack Lloyd
*
* Released under the terms of the Botan license
*/

#include <botan/tls_messages.h>
#include <botan/pubkey.h>
#include <botan/dh.h>
#include <botan/rsa.h>
#include <botan/dsa.h>
#include <botan/loadstor.h>
#include <memory>

namespace Botan {

/**
* Create a new Server Key Exchange message
*/
Server_Key_Exchange::Server_Key_Exchange(RandomNumberGenerator& rng,
                                         Record_Writer& writer,
                                         const Public_Key* kex_key,
                                         const Private_Key* priv_key,
                                         const MemoryRegion<byte>& c_random,
                                         const MemoryRegion<byte>& s_random,
                                         HandshakeHash& hash)
   {
   const DH_PublicKey* dh_pub = dynamic_cast<const DH_PublicKey*>(kex_key);
   const RSA_PublicKey* rsa_pub = dynamic_cast<const RSA_PublicKey*>(kex_key);

   if(dh_pub)
      {
      params.push_back(dh_pub->get_domain().get_p());
      params.push_back(dh_pub->get_domain().get_g());
      params.push_back(BigInt::decode(dh_pub->public_value()));
      }
   else if(rsa_pub)
      {
      params.push_back(rsa_pub->get_n());
      params.push_back(rsa_pub->get_e());
      }
   else
      throw Invalid_Argument("Bad key for TLS key exchange: not DH or RSA");

   std::string padding = "";
   Signature_Format format = IEEE_1363;

   if(priv_key->algo_name() == "RSA")
      padding = "EMSA3(TLS.Digest.0)";
   else if(priv_key->algo_name() == "DSA")
      {
      padding = "EMSA1(SHA-1)";
      format = DER_SEQUENCE;
      }
   else
      throw Invalid_Argument(priv_key->algo_name() +
                             " is invalid/unknown for TLS signatures");

   PK_Signer signer(*priv_key, padding, format);

   signer.update(c_random);
   signer.update(s_random);
   signer.update(serialize_params());
   signature = signer.signature(rng);

   send(writer, hash);
   }

/**
* Serialize a Server Key Exchange message
*/
SecureVector<byte> Server_Key_Exchange::serialize() const
   {
   SecureVector<byte> buf = serialize_params();
   u16bit sig_len = signature.size();
   buf.append(get_byte(0, sig_len));
   buf.append(get_byte(1, sig_len));
   buf.append(signature);
   return buf;
   }

/**
* Serialize the ServerParams structure
*/
SecureVector<byte> Server_Key_Exchange::serialize_params() const
   {
   SecureVector<byte> buf;
   for(u32bit j = 0; j != params.size(); j++)
      {
      SecureVector<byte> param = BigInt::encode(params[j]);
      u16bit param_size = param.size();

      buf.append(get_byte(0, param_size));
      buf.append(get_byte(1, param_size));
      buf.append(param);
      }
   return buf;
   }

/**
* Deserialize a Server Key Exchange message
*/
void Server_Key_Exchange::deserialize(const MemoryRegion<byte>& buf)
   {
   if(buf.size() < 6)
      throw Decoding_Error("Server_Key_Exchange: Packet corrupted");

   SecureVector<byte> values[4];
   u32bit so_far = 0;

   for(u32bit j = 0; j != 4; j++)
      {
      u16bit len = make_u16bit(buf[so_far], buf[so_far+1]);
      so_far += 2;

      if(len + so_far > buf.size())
         throw Decoding_Error("Server_Key_Exchange: Packet corrupted");

      values[j].set(buf + so_far, len);
      so_far += len;

      if(j == 2 && so_far == buf.size())
         break;
      }

   params.push_back(BigInt::decode(values[0]));
   params.push_back(BigInt::decode(values[1]));
   if(values[3].size())
      {
      params.push_back(BigInt::decode(values[2]));
      signature = values[3];
      }
   else
      signature = values[2];
   }

/**
* Return the public key
*/
Public_Key* Server_Key_Exchange::key() const
   {
   if(params.size() == 2)
      return new RSA_PublicKey(params[0], params[1]);
   else if(params.size() == 3)
      return new DH_PublicKey(DL_Group(params[0], params[1]), params[2]);
   else
      throw Internal_Error("Server_Key_Exchange::key: No key set");
   }

/**
* Verify a Server Key Exchange message
*/
bool Server_Key_Exchange::verify(const X509_Certificate& cert,
                                 const MemoryRegion<byte>& c_random,
                                 const MemoryRegion<byte>& s_random) const
   {

   std::auto_ptr<Public_Key> key(cert.subject_public_key());

   std::string padding = "";
   Signature_Format format = IEEE_1363;

   if(key->algo_name() == "RSA")
      padding = "EMSA3(TLS.Digest.0)";
   else if(key->algo_name() == "DSA")
      {
      padding == "EMSA1(SHA-1)";
      format = DER_SEQUENCE;
      }
   else
      throw Invalid_Argument(key->algo_name() +
                             " is invalid/unknown for TLS signatures");

   PK_Verifier verifier(*key, padding, format);

   SecureVector<byte> params_got = serialize_params();
   verifier.update(c_random);
   verifier.update(s_random);
   verifier.update(params_got);

   return verifier.check_signature(signature, signature.size());
   }

}
<|endoftext|>


<commit_before><commit_msg>test/rados-api/snapshots.cc:RollbackPP<commit_after><|endoftext|>


<commit_before>//===--- TypeInfo.cpp - Type information relevant to SILGen -----*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

#include "SILGen.h"
#include "TypeInfo.h"
#include "TypeVisitor.h"
#include "swift/AST/ASTContext.h"
#include "swift/AST/Types.h"

namespace swift {
namespace Lowering {

static bool isAddressOnly(Type t) {
  // Archetypes and existentials are always address-only.
  // FIXME: Class archetypes and existentials will one day be representable as
  // reference types.
  // FIXME: resilient structs
  return t->is<ArchetypeType>() || t->isExistentialType();
}

namespace {
  enum Loadable_t { IsAddressOnly, IsLoadable };
}

/// LoadableTypeInfoVisitor - Recursively descend into fragile struct and
/// tuple types and visit their element types, storing information about the
/// reference type members in the TypeInfo for the type.
class LoadableTypeInfoVisitor : public TypeVisitor<LoadableTypeInfoVisitor,
                                                   Loadable_t>
{
  TypeInfo &theInfo;
  ReferenceTypeElement currentElement;
public:
  LoadableTypeInfoVisitor(TypeInfo &theInfo) : theInfo(theInfo) {}

  void pushPath() { currentElement.path.push_back({Type(), 0}); }
  void popPath() { currentElement.path.pop_back(); }
  void setPathType(Type t) { currentElement.path.back().type = t; }
  void advancePath() { ++currentElement.path.back().index; }

  Loadable_t visitType(TypeBase *t) {
    if (t->hasReferenceSemantics()) {
      theInfo.referenceTypeElements.push_back(currentElement);
      return IsLoadable;
    }
    if (isAddressOnly(t))
      return IsAddressOnly;
    return IsLoadable;
  }

  Loadable_t visitNominalType(NominalType *t) {
    if (StructDecl *sd = dyn_cast<StructDecl>(t->getDecl())) {
      // FIXME: if this struct has a resilient attribute, mark the TypeInfo
      // as addressOnly and bail.

      pushPath();
      for (Decl *d : sd->getMembers())
        if (VarDecl *vd = dyn_cast<VarDecl>(d))
          if (!vd->isProperty()) {
            CanType ct = vd->getType()->getCanonicalType();
            setPathType(ct);
            if (visit(ct) == IsAddressOnly) {
              return IsAddressOnly;
            }
            advancePath();
          }
      popPath();
      return IsLoadable;
    } else
      return this->visitType(t);
  }

  Loadable_t visitTupleType(TupleType *t) {
    pushPath();
    for (TupleTypeElt const &elt : t->getFields()) {
      CanType ct = elt.getType()->getCanonicalType();
      setPathType(ct);

      visit(ct);
      // FIXME: Address-only tuples complicate function argument handling a bit.
      // Consider all tuples loadable for now, even though this is broken.
      /*
      if (visit(ct) == IsAddressOnly) {
        return IsAddressOnly;
      }
       */
      advancePath();
    }
    popPath();
    return IsLoadable;
  }
};

TypeConverter::TypeConverter(SILGenModule &sgm)
  : Context(sgm.M.getContext()) {
}

void TypeConverter::makeFragileElementsForDecl(TypeInfo &theInfo,
                                               NominalTypeDecl *decl) {
  unsigned elementIndex = 0;
  for (Decl *d : decl->getMembers()) {
    if (VarDecl *vd = dyn_cast<VarDecl>(d)) {
      if (!vd->isProperty()) {
        theInfo.fragileElements[vd->getName()] = {vd->getType(),
          elementIndex};
        ++elementIndex;
      }
    }
  }
}

void TypeConverter::makeFragileElements(TypeInfo &theInfo, CanType t) {
  // FIXME: check resilient attribute
  if (NominalType *nt = t->getAs<NominalType>()) {
    makeFragileElementsForDecl(theInfo, nt->getDecl());
  } else if (BoundGenericType *bgt = t->getAs<BoundGenericType>()) {
    makeFragileElementsForDecl(theInfo, bgt->getDecl());
  }
}

TypeInfo const &TypeConverter::makeTypeInfo(CanType t) {
  TypeInfo &theInfo = types[t.getPointer()];
  bool address = false;
  bool addressOnly = false;

  if (LValueType *lvt = t->getAs<LValueType>()) {
    t = lvt->getObjectType()->getCanonicalType();
    address = true;
    addressOnly = getTypeInfo(t).isAddressOnly();
  } else if (t->hasReferenceSemantics()) {
    // Reference types are always loadable, and need only to retain/release
    // themselves.
    addressOnly = false;
    theInfo.referenceTypeElements.push_back(ReferenceTypeElement());
  } else if (isAddressOnly(t)) {
    addressOnly = true;
  } else {
    // walk aggregate types to determine address-only-ness and find reference
    // type elements.
    addressOnly =
      LoadableTypeInfoVisitor(theInfo).visit(t) == IsAddressOnly;
    if (addressOnly)
      theInfo.referenceTypeElements.clear();
  }
  // If this is a struct or class type, find its fragile elements.
  makeFragileElements(theInfo, t);

  // Generate the lowered type.
  theInfo.loweredType = SILType(t,
                                /*address=*/address || addressOnly,
                                /*loadable=*/!addressOnly);

  return theInfo;
}

TypeInfo const &TypeConverter::getTypeInfo(Type t) {
  CanType ct = t->getCanonicalType();
  auto existing = types.find(ct.getPointer());
  if (existing == types.end()) {
    return makeTypeInfo(ct);
  } else
    return existing->second;
}

SILType TypeConverter::getConstantType(SILConstant constant) {
  auto found = constantTypes.find(constant);
  if (found == constantTypes.end()) {
    Type swiftTy = makeConstantType(constant);
    SILType loweredTy = getTypeInfo(swiftTy).getLoweredType();
    constantTypes[constant] = loweredTy;
    return loweredTy;
  } else
    return found->second;
}

/// Get the type of a property accessor, () -> T for a getter or (value:T) -> ()
/// for a setter.
Type TypeConverter::getPropertyType(unsigned id, Type valueType) const {
  if (id & SILConstant::Getter) {
    return FunctionType::get(TupleType::getEmpty(Context), valueType, Context);
  }
  if (id & SILConstant::Setter) {
    TupleTypeElt valueParam(valueType, Context.getIdentifier("value"));
    return FunctionType::get(TupleType::get(valueParam, Context),
                             TupleType::getEmpty(Context),
                             Context);
  }
  llvm_unreachable("not a property constant");
}

/// Get the type of a subscript accessor, Index -> PropertyAccessor.
Type TypeConverter::getSubscriptPropertyType(unsigned id,
                                     Type indexType,
                                     Type elementType) const {
  Type propertyType = getPropertyType(id, elementType);
  return FunctionType::get(indexType, propertyType, Context);
}

/// Get the type of the 'this' parameter for methods of a type.
Type TypeConverter::getMethodThisType(Type thisType) const {
  if (thisType->hasReferenceSemantics()) {
    return thisType;
  } else {
    return LValueType::get(thisType, LValueType::Qual::DefaultForType, Context);
  }
}

Type TypeConverter::getMethodTypeInContext(Type /*nullable*/ contextType,
                                       Type methodType) const {
  if (!contextType)
    return methodType;
  Type thisType = getMethodThisType(contextType);

  if (UnboundGenericType *ugt = contextType->getAs<UnboundGenericType>()) {
    return PolymorphicFunctionType::get(thisType, methodType,
                                        ugt->getDecl()->getGenericParams(),
                                        Context);
  }

  return FunctionType::get(thisType, methodType, Context);
}

/// Get the type of a global variable accessor function, () -> [byref] T.
static Type getGlobalAccessorType(Type varAddressType, ASTContext &C) {
  return FunctionType::get(TupleType::getEmpty(C),
                           varAddressType, C);
}

Type TypeConverter::makeConstantType(SILConstant c) {
  // TODO: mangle function types for address-only indirect arguments and returns
  if (ValueDecl *vd = c.loc.dyn_cast<ValueDecl*>()) {
    Type /*nullable*/ contextType =
      vd->getDeclContext()->getDeclaredTypeOfContext();
    if (SubscriptDecl *sd = dyn_cast<SubscriptDecl>(vd)) {
      // If this is a subscript accessor, derive the accessor type.
      Type subscriptType = getSubscriptPropertyType(c.id,
                                                    sd->getIndices()->getType(),
                                                    sd->getElementType());
      return getMethodTypeInContext(contextType, subscriptType);
    } else {
      Type propertyType;
      // If this is a property accessor, derive the property type.
      if (c.id & (SILConstant::Getter | SILConstant::Setter)) {
        Type propertyType = getPropertyType(c.id, vd->getType());
        return getMethodTypeInContext(contextType, propertyType);
      }

      // If it's a global var, derive the initializer/accessor function type
      // () -> [byref] T
      if (VarDecl *var = dyn_cast<VarDecl>(vd)) {
        assert(!var->isProperty() && "constant ref to non-physical global var");
        return getGlobalAccessorType(var->getTypeOfReference(), Context);
      }

      // Otherwise, return the Swift-level type.
      return vd->getTypeOfReference();
    }
  } else if (CapturingExpr *e = c.loc.dyn_cast<CapturingExpr*>()) {
    return e->getType();
  }
  llvm_unreachable("unexpected constant loc");
}

} // namespace Lowering
} // namespace swift
<commit_msg>SILGen: Fix type of global variable accessors. Emit global accessors as type '() -> [byref] T' instead of '() -> [byref(heap)] T' so that the SIL verifier doesn't stumble on unequal LValueTypes.<commit_after>//===--- TypeInfo.cpp - Type information relevant to SILGen -----*- C++ -*-===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See http://swift.org/LICENSE.txt for license information
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

#include "SILGen.h"
#include "TypeInfo.h"
#include "TypeVisitor.h"
#include "swift/AST/ASTContext.h"
#include "swift/AST/Types.h"

namespace swift {
namespace Lowering {

static bool isAddressOnly(Type t) {
  // Archetypes and existentials are always address-only.
  // FIXME: Class archetypes and existentials will one day be representable as
  // reference types.
  // FIXME: resilient structs
  return t->is<ArchetypeType>() || t->isExistentialType();
}

namespace {
  enum Loadable_t { IsAddressOnly, IsLoadable };
}

/// LoadableTypeInfoVisitor - Recursively descend into fragile struct and
/// tuple types and visit their element types, storing information about the
/// reference type members in the TypeInfo for the type.
class LoadableTypeInfoVisitor : public TypeVisitor<LoadableTypeInfoVisitor,
                                                   Loadable_t>
{
  TypeInfo &theInfo;
  ReferenceTypeElement currentElement;
public:
  LoadableTypeInfoVisitor(TypeInfo &theInfo) : theInfo(theInfo) {}

  void pushPath() { currentElement.path.push_back({Type(), 0}); }
  void popPath() { currentElement.path.pop_back(); }
  void setPathType(Type t) { currentElement.path.back().type = t; }
  void advancePath() { ++currentElement.path.back().index; }

  Loadable_t visitType(TypeBase *t) {
    if (t->hasReferenceSemantics()) {
      theInfo.referenceTypeElements.push_back(currentElement);
      return IsLoadable;
    }
    if (isAddressOnly(t))
      return IsAddressOnly;
    return IsLoadable;
  }

  Loadable_t visitNominalType(NominalType *t) {
    if (StructDecl *sd = dyn_cast<StructDecl>(t->getDecl())) {
      // FIXME: if this struct has a resilient attribute, mark the TypeInfo
      // as addressOnly and bail.

      pushPath();
      for (Decl *d : sd->getMembers())
        if (VarDecl *vd = dyn_cast<VarDecl>(d))
          if (!vd->isProperty()) {
            CanType ct = vd->getType()->getCanonicalType();
            setPathType(ct);
            if (visit(ct) == IsAddressOnly) {
              return IsAddressOnly;
            }
            advancePath();
          }
      popPath();
      return IsLoadable;
    } else
      return this->visitType(t);
  }

  Loadable_t visitTupleType(TupleType *t) {
    pushPath();
    for (TupleTypeElt const &elt : t->getFields()) {
      CanType ct = elt.getType()->getCanonicalType();
      setPathType(ct);

      visit(ct);
      // FIXME: Address-only tuples complicate function argument handling a bit.
      // Consider all tuples loadable for now, even though this is broken.
      /*
      if (visit(ct) == IsAddressOnly) {
        return IsAddressOnly;
      }
       */
      advancePath();
    }
    popPath();
    return IsLoadable;
  }
};

TypeConverter::TypeConverter(SILGenModule &sgm)
  : Context(sgm.M.getContext()) {
}

void TypeConverter::makeFragileElementsForDecl(TypeInfo &theInfo,
                                               NominalTypeDecl *decl) {
  unsigned elementIndex = 0;
  for (Decl *d : decl->getMembers()) {
    if (VarDecl *vd = dyn_cast<VarDecl>(d)) {
      if (!vd->isProperty()) {
        theInfo.fragileElements[vd->getName()] = {vd->getType(),
          elementIndex};
        ++elementIndex;
      }
    }
  }
}

void TypeConverter::makeFragileElements(TypeInfo &theInfo, CanType t) {
  // FIXME: check resilient attribute
  if (NominalType *nt = t->getAs<NominalType>()) {
    makeFragileElementsForDecl(theInfo, nt->getDecl());
  } else if (BoundGenericType *bgt = t->getAs<BoundGenericType>()) {
    makeFragileElementsForDecl(theInfo, bgt->getDecl());
  }
}

TypeInfo const &TypeConverter::makeTypeInfo(CanType t) {
  TypeInfo &theInfo = types[t.getPointer()];
  bool address = false;
  bool addressOnly = false;

  if (LValueType *lvt = t->getAs<LValueType>()) {
    t = lvt->getObjectType()->getCanonicalType();
    address = true;
    addressOnly = getTypeInfo(t).isAddressOnly();
  } else if (t->hasReferenceSemantics()) {
    // Reference types are always loadable, and need only to retain/release
    // themselves.
    addressOnly = false;
    theInfo.referenceTypeElements.push_back(ReferenceTypeElement());
  } else if (isAddressOnly(t)) {
    addressOnly = true;
  } else {
    // walk aggregate types to determine address-only-ness and find reference
    // type elements.
    addressOnly =
      LoadableTypeInfoVisitor(theInfo).visit(t) == IsAddressOnly;
    if (addressOnly)
      theInfo.referenceTypeElements.clear();
  }
  // If this is a struct or class type, find its fragile elements.
  makeFragileElements(theInfo, t);

  // Generate the lowered type.
  theInfo.loweredType = SILType(t,
                                /*address=*/address || addressOnly,
                                /*loadable=*/!addressOnly);

  return theInfo;
}

TypeInfo const &TypeConverter::getTypeInfo(Type t) {
  CanType ct = t->getCanonicalType();
  auto existing = types.find(ct.getPointer());
  if (existing == types.end()) {
    return makeTypeInfo(ct);
  } else
    return existing->second;
}

SILType TypeConverter::getConstantType(SILConstant constant) {
  auto found = constantTypes.find(constant);
  if (found == constantTypes.end()) {
    Type swiftTy = makeConstantType(constant);
    SILType loweredTy = getTypeInfo(swiftTy).getLoweredType();
    constantTypes[constant] = loweredTy;
    return loweredTy;
  } else
    return found->second;
}

/// Get the type of a property accessor, () -> T for a getter or (value:T) -> ()
/// for a setter.
Type TypeConverter::getPropertyType(unsigned id, Type valueType) const {
  if (id & SILConstant::Getter) {
    return FunctionType::get(TupleType::getEmpty(Context), valueType, Context);
  }
  if (id & SILConstant::Setter) {
    TupleTypeElt valueParam(valueType, Context.getIdentifier("value"));
    return FunctionType::get(TupleType::get(valueParam, Context),
                             TupleType::getEmpty(Context),
                             Context);
  }
  llvm_unreachable("not a property constant");
}

/// Get the type of a subscript accessor, Index -> PropertyAccessor.
Type TypeConverter::getSubscriptPropertyType(unsigned id,
                                     Type indexType,
                                     Type elementType) const {
  Type propertyType = getPropertyType(id, elementType);
  return FunctionType::get(indexType, propertyType, Context);
}

/// Get the type of the 'this' parameter for methods of a type.
Type TypeConverter::getMethodThisType(Type thisType) const {
  if (thisType->hasReferenceSemantics()) {
    return thisType;
  } else {
    return LValueType::get(thisType, LValueType::Qual::DefaultForType, Context);
  }
}

Type TypeConverter::getMethodTypeInContext(Type /*nullable*/ contextType,
                                       Type methodType) const {
  if (!contextType)
    return methodType;
  Type thisType = getMethodThisType(contextType);

  if (UnboundGenericType *ugt = contextType->getAs<UnboundGenericType>()) {
    return PolymorphicFunctionType::get(thisType, methodType,
                                        ugt->getDecl()->getGenericParams(),
                                        Context);
  }

  return FunctionType::get(thisType, methodType, Context);
}

/// Get the type of a global variable accessor function, () -> [byref] T.
static Type getGlobalAccessorType(Type varType, ASTContext &C) {
  return FunctionType::get(TupleType::getEmpty(C),
                           LValueType::get(varType,
                                           LValueType::Qual::DefaultForType,
                                           C),
                           C);
}

Type TypeConverter::makeConstantType(SILConstant c) {
  // TODO: mangle function types for address-only indirect arguments and returns
  if (ValueDecl *vd = c.loc.dyn_cast<ValueDecl*>()) {
    Type /*nullable*/ contextType =
      vd->getDeclContext()->getDeclaredTypeOfContext();
    if (SubscriptDecl *sd = dyn_cast<SubscriptDecl>(vd)) {
      // If this is a subscript accessor, derive the accessor type.
      Type subscriptType = getSubscriptPropertyType(c.id,
                                                    sd->getIndices()->getType(),
                                                    sd->getElementType());
      return getMethodTypeInContext(contextType, subscriptType);
    } else {
      Type propertyType;
      // If this is a property accessor, derive the property type.
      if (c.id & (SILConstant::Getter | SILConstant::Setter)) {
        Type propertyType = getPropertyType(c.id, vd->getType());
        return getMethodTypeInContext(contextType, propertyType);
      }

      // If it's a global var, derive the initializer/accessor function type
      // () -> [byref] T
      if (VarDecl *var = dyn_cast<VarDecl>(vd)) {
        assert(!var->isProperty() && "constant ref to non-physical global var");
        return getGlobalAccessorType(var->getType(), Context);
      }

      // Otherwise, return the Swift-level type.
      return vd->getTypeOfReference();
    }
  } else if (CapturingExpr *e = c.loc.dyn_cast<CapturingExpr*>()) {
    return e->getType();
  }
  llvm_unreachable("unexpected constant loc");
}

} // namespace Lowering
} // namespace swift
<|endoftext|>


<commit_before>//===--- SILGenEpilog.cpp - Function epilogue emission --------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

#include "SILGen.h"
#include "SILGenFunction.h"
#include "ASTVisitor.h"
#include "swift/SIL/SILArgument.h"

using namespace swift;
using namespace Lowering;

void SILGenFunction::prepareEpilog(Type resultType, bool isThrowing,
                                   CleanupLocation CleanupL) {
  auto *epilogBB = createBasicBlock();

  // If we have any direct results, receive them via BB arguments.
  // But callers can disable this by passing a null result type.
  if (resultType) {
    auto fnConv = F.getConventions();
    // Set NeedsReturn for indirect or direct results. This ensures that SILGen
    // emits unreachable if there is no source level return.
    NeedsReturn = (fnConv.funcTy->getNumResults() != 0);
    for (auto directResult : fnConv.getDirectSILResults()) {
      SILType resultType =
          F.mapTypeIntoContext(fnConv.getSILType(directResult));
      epilogBB->createPHIArgument(resultType, ValueOwnershipKind::Owned);
    }
  }

  ReturnDest = JumpDest(epilogBB, getCleanupsDepth(), CleanupL);

  if (isThrowing) {
    prepareRethrowEpilog(CleanupL);
  }
}

void SILGenFunction::prepareRethrowEpilog(CleanupLocation cleanupLoc) {
  auto exnType = SILType::getExceptionType(getASTContext());
  SILBasicBlock *rethrowBB = createBasicBlock(FunctionSection::Postmatter);
  rethrowBB->createPHIArgument(exnType, ValueOwnershipKind::Owned);
  ThrowDest = JumpDest(rethrowBB, getCleanupsDepth(), cleanupLoc);
}

/// Given a list of direct results, form the direct result value.
///
/// Note that this intentionally loses any tuple sub-structure of the
/// formal result type.
static SILValue buildReturnValue(SILGenFunction &SGF, SILLocation loc,
                                 ArrayRef<SILValue> directResults) {
  if (directResults.size() == 1)
    return directResults[0];

  SmallVector<TupleTypeElt, 4> eltTypes;
  for (auto elt : directResults)
    eltTypes.push_back(elt->getType().getSwiftRValueType());
  auto resultType = SILType::getPrimitiveObjectType(
    CanType(TupleType::get(eltTypes, SGF.getASTContext())));
  return SGF.B.createTuple(loc, resultType, directResults);
}

std::pair<Optional<SILValue>, SILLocation>
SILGenFunction::emitEpilogBB(SILLocation TopLevel) {
  assert(ReturnDest.getBlock() && "no epilog bb prepared?!");
  SILBasicBlock *epilogBB = ReturnDest.getBlock();
  SILLocation ImplicitReturnFromTopLevel =
    ImplicitReturnLocation::getImplicitReturnLoc(TopLevel);
  SmallVector<SILValue, 4> directResults;
  Optional<SILLocation> returnLoc = None;

  // If the current BB isn't terminated, and we require a return, then we
  // are not allowed to fall off the end of the function and can't reach here.
  if (NeedsReturn && B.hasValidInsertionPoint())
    B.createUnreachable(ImplicitReturnFromTopLevel);

  if (epilogBB->pred_empty()) {
    // If the epilog was not branched to at all, kill the BB and
    // just emit the epilog into the current BB.
    while (!epilogBB->empty())
      epilogBB->back().eraseFromParent();
    eraseBasicBlock(epilogBB);

    // If the current bb is terminated then the epilog is just unreachable.
    if (!B.hasValidInsertionPoint())
      return { None, TopLevel };

    // We emit the epilog at the current insertion point.
    returnLoc = ImplicitReturnFromTopLevel;

  } else if (std::next(epilogBB->pred_begin()) == epilogBB->pred_end()
             && !B.hasValidInsertionPoint()) {
    // If the epilog has a single predecessor and there's no current insertion
    // point to fall through from, then we can weld the epilog to that
    // predecessor BB.

    // Steal the branch argument as the return value if present.
    SILBasicBlock *pred = *epilogBB->pred_begin();
    BranchInst *predBranch = cast<BranchInst>(pred->getTerminator());
    assert(predBranch->getArgs().size() == epilogBB->args_size() &&
           "epilog predecessor arguments does not match block params");

    for (auto index : indices(predBranch->getArgs())) {
      SILValue result = predBranch->getArgs()[index];
      directResults.push_back(result);
      epilogBB->getArgument(index)->replaceAllUsesWith(result);
    }

    // If we are optimizing, we should use the return location from the single,
    // previously processed, return statement if any.
    if (predBranch->getLoc().is<ReturnLocation>()) {
      returnLoc = predBranch->getLoc();
    } else {
      returnLoc = ImplicitReturnFromTopLevel;
    }

    // Kill the branch to the now-dead epilog BB.
    pred->erase(predBranch);

    // Move any instructions from the EpilogBB to the end of the 'pred' block.
    pred->spliceAtEnd(epilogBB);

    // Finally we can erase the epilog BB.
    eraseBasicBlock(epilogBB);

    // Emit the epilog into its former predecessor.
    B.setInsertionPoint(pred);
  } else {
    // Move the epilog block to the end of the ordinary section.
    auto endOfOrdinarySection = StartOfPostmatter;
    B.moveBlockTo(epilogBB, endOfOrdinarySection);

    // Emit the epilog into the epilog bb. Its arguments are the
    // direct results.
    directResults.append(epilogBB->args_begin(), epilogBB->args_end());

    // If we are falling through from the current block, the return is implicit.
    B.emitBlock(epilogBB, ImplicitReturnFromTopLevel);
  }

  // Emit top-level cleanups into the epilog block.
  assert(!Cleanups.hasAnyActiveCleanups(getCleanupsDepth(),
                                        ReturnDest.getDepth()) &&
         "emitting epilog in wrong scope");

  auto cleanupLoc = CleanupLocation::get(TopLevel);
  Cleanups.emitCleanupsForReturn(cleanupLoc);

  // If the return location is known to be that of an already
  // processed return, use it. (This will get triggered when the
  // epilog logic is simplified.)
  //
  // Otherwise make the ret instruction part of the cleanups.
  if (!returnLoc) returnLoc = cleanupLoc;

  // Build the return value.  We don't do this if there are no direct
  // results; this can happen for void functions, but also happens when
  // prepareEpilog was asked to not add result arguments to the epilog
  // block.
  SILValue returnValue;
  if (!directResults.empty()) {
    assert(directResults.size() == F.getConventions().getNumDirectSILResults());
    returnValue = buildReturnValue(*this, TopLevel, directResults);
  }

  return { returnValue, *returnLoc };
}

SILLocation SILGenFunction::
emitEpilog(SILLocation TopLevel, bool UsesCustomEpilog) {
  Optional<SILValue> maybeReturnValue;
  SILLocation returnLoc(TopLevel);
  std::tie(maybeReturnValue, returnLoc) = emitEpilogBB(TopLevel);

  SILBasicBlock *ResultBB = nullptr;

  if (!maybeReturnValue) {
    // Nothing to do.
  } else if (UsesCustomEpilog) {
    // If the epilog is reachable, and the caller provided an epilog, just
    // remember the block so the caller can continue it.
    ResultBB = B.getInsertionBB();
    assert(ResultBB && "Didn't have an epilog block?");
    B.clearInsertionPoint();
  } else {
    // Otherwise, if the epilog block is reachable, return the return value.
    SILValue returnValue = *maybeReturnValue;

    // Return () if no return value was given.
    if (!returnValue)
      returnValue = emitEmptyTuple(CleanupLocation::get(TopLevel));

    B.createReturn(returnLoc, returnValue);
  }

  emitRethrowEpilog(TopLevel);

  if (ResultBB)
    B.setInsertionPoint(ResultBB);

  return returnLoc;
}

void SILGenFunction::emitRethrowEpilog(SILLocation topLevel) {
  assert(!B.hasValidInsertionPoint());

  // If we don't have a rethrow destination, we're done.
  if (!ThrowDest.isValid())
    return;

  // If the rethrow destination isn't used, we're done.
  SILBasicBlock *rethrowBB = ThrowDest.getBlock();
  if (rethrowBB->pred_empty()) {
    ThrowDest = JumpDest::invalid();
    eraseBasicBlock(rethrowBB);
    return;
  }

  SILLocation throwLoc = topLevel;
  SILValue exn = rethrowBB->args_begin()[0];
  bool reposition = true;

  // If the rethrow destination has a single branch predecessor,
  // consider emitting the rethrow into it.
  SILBasicBlock *predBB = *rethrowBB->pred_begin();
  if (std::next(rethrowBB->pred_begin()) == rethrowBB->pred_end()) {
    if (auto branch = dyn_cast<BranchInst>(predBB->getTerminator())) {
      assert(branch->getArgs().size() == 1);

      // Save the location and operand information from the branch,
      // then destroy it.
      throwLoc = branch->getLoc();
      exn = branch->getArgs()[0];
      predBB->erase(branch);

      // Erase the rethrow block.
      eraseBasicBlock(rethrowBB);
      rethrowBB = predBB;
      reposition = false;
    }
  }

  // Reposition the rethrow block to the end of the postmatter section
  // unless we're emitting into a single predecessor.
  if (reposition) {
    B.moveBlockTo(rethrowBB, F.end());
  }

  B.setInsertionPoint(rethrowBB);
  Cleanups.emitCleanupsForReturn(ThrowDest.getCleanupLocation());

  B.createThrow(throwLoc, exn);

  ThrowDest = JumpDest::invalid();
}
<commit_msg>[silgen] Split out long logic in emitEpilogBB into a helper function so we can use early returns to simplify the logic.<commit_after>//===--- SILGenEpilog.cpp - Function epilogue emission --------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//

#include "SILGen.h"
#include "SILGenFunction.h"
#include "ASTVisitor.h"
#include "swift/SIL/SILArgument.h"

using namespace swift;
using namespace Lowering;

void SILGenFunction::prepareEpilog(Type resultType, bool isThrowing,
                                   CleanupLocation CleanupL) {
  auto *epilogBB = createBasicBlock();

  // If we have any direct results, receive them via BB arguments.
  // But callers can disable this by passing a null result type.
  if (resultType) {
    auto fnConv = F.getConventions();
    // Set NeedsReturn for indirect or direct results. This ensures that SILGen
    // emits unreachable if there is no source level return.
    NeedsReturn = (fnConv.funcTy->getNumResults() != 0);
    for (auto directResult : fnConv.getDirectSILResults()) {
      SILType resultType =
          F.mapTypeIntoContext(fnConv.getSILType(directResult));
      epilogBB->createPHIArgument(resultType, ValueOwnershipKind::Owned);
    }
  }

  ReturnDest = JumpDest(epilogBB, getCleanupsDepth(), CleanupL);

  if (isThrowing) {
    prepareRethrowEpilog(CleanupL);
  }
}

void SILGenFunction::prepareRethrowEpilog(CleanupLocation cleanupLoc) {
  auto exnType = SILType::getExceptionType(getASTContext());
  SILBasicBlock *rethrowBB = createBasicBlock(FunctionSection::Postmatter);
  rethrowBB->createPHIArgument(exnType, ValueOwnershipKind::Owned);
  ThrowDest = JumpDest(rethrowBB, getCleanupsDepth(), cleanupLoc);
}

/// Given a list of direct results, form the direct result value.
///
/// Note that this intentionally loses any tuple sub-structure of the
/// formal result type.
static SILValue buildReturnValue(SILGenFunction &SGF, SILLocation loc,
                                 ArrayRef<SILValue> directResults) {
  if (directResults.size() == 1)
    return directResults[0];

  SmallVector<TupleTypeElt, 4> eltTypes;
  for (auto elt : directResults)
    eltTypes.push_back(elt->getType().getSwiftRValueType());
  auto resultType = SILType::getPrimitiveObjectType(
    CanType(TupleType::get(eltTypes, SGF.getASTContext())));
  return SGF.B.createTuple(loc, resultType, directResults);
}

static Optional<SILLocation>
prepareForEpilogBlockEmission(SILGenFunction &SGF, SILLocation topLevel,
                              SILBasicBlock *epilogBB,
                              SmallVectorImpl<SILValue> &directResults) {
  SILLocation implicitReturnFromTopLevel =
      ImplicitReturnLocation::getImplicitReturnLoc(topLevel);

  // If the current BB we are inserting into isn't terminated, and we require a
  // return, then we
  // are not allowed to fall off the end of the function and can't reach here.
  if (SGF.NeedsReturn && SGF.B.hasValidInsertionPoint())
    SGF.B.createUnreachable(implicitReturnFromTopLevel);

  if (epilogBB->pred_empty()) {
    // If the epilog was not branched to at all, kill the BB and
    // just emit the epilog into the current BB.
    while (!epilogBB->empty())
      epilogBB->back().eraseFromParent();
    SGF.eraseBasicBlock(epilogBB);

    // If the current bb is terminated then the epilog is just unreachable.
    if (!SGF.B.hasValidInsertionPoint())
      return None;

    // We emit the epilog at the current insertion point.
    return implicitReturnFromTopLevel;
  }

  if (std::next(epilogBB->pred_begin()) == epilogBB->pred_end() &&
      !SGF.B.hasValidInsertionPoint()) {
    // If the epilog has a single predecessor and there's no current insertion
    // point to fall through from, then we can weld the epilog to that
    // predecessor BB.

    // Steal the branch argument as the return value if present.
    SILBasicBlock *pred = *epilogBB->pred_begin();
    BranchInst *predBranch = cast<BranchInst>(pred->getTerminator());
    assert(predBranch->getArgs().size() == epilogBB->args_size() &&
           "epilog predecessor arguments does not match block params");

    for (auto index : indices(predBranch->getArgs())) {
      SILValue result = predBranch->getArgs()[index];
      directResults.push_back(result);
      epilogBB->getArgument(index)->replaceAllUsesWith(result);
    }

    Optional<SILLocation> returnLoc;
    // If we are optimizing, we should use the return location from the single,
    // previously processed, return statement if any.
    if (predBranch->getLoc().is<ReturnLocation>()) {
      returnLoc = predBranch->getLoc();
    } else {
      returnLoc = implicitReturnFromTopLevel;
    }

    // Kill the branch to the now-dead epilog BB.
    pred->erase(predBranch);

    // Move any instructions from the EpilogBB to the end of the 'pred' block.
    pred->spliceAtEnd(epilogBB);

    // Finally we can erase the epilog BB.
    SGF.eraseBasicBlock(epilogBB);

    // Emit the epilog into its former predecessor.
    SGF.B.setInsertionPoint(pred);
    return returnLoc;
  }

  // Move the epilog block to the end of the ordinary section.
  auto endOfOrdinarySection = SGF.StartOfPostmatter;
  SGF.B.moveBlockTo(epilogBB, endOfOrdinarySection);

  // Emit the epilog into the epilog bb. Its arguments are the
  // direct results.
  directResults.append(epilogBB->args_begin(), epilogBB->args_end());

  // If we are falling through from the current block, the return is implicit.
  SGF.B.emitBlock(epilogBB, implicitReturnFromTopLevel);

  // If the return location is known to be that of an already
  // processed return, use it. (This will get triggered when the
  // epilog logic is simplified.)
  //
  // Otherwise make the ret instruction part of the cleanups.
  auto cleanupLoc = CleanupLocation::get(topLevel);
  return cleanupLoc;
}

std::pair<Optional<SILValue>, SILLocation>
SILGenFunction::emitEpilogBB(SILLocation topLevel) {
  assert(ReturnDest.getBlock() && "no epilog bb prepared?!");
  SILBasicBlock *epilogBB = ReturnDest.getBlock();
  SmallVector<SILValue, 8> directResults;

  // Prepare the epilog block for emission. If we need to actually emit the
  // block, we return a real SILLocation. Otherwise, the epilog block is
  // actually unreachable and we can just return early.
  auto returnLoc =
      prepareForEpilogBlockEmission(*this, topLevel, epilogBB, directResults);
  if (!returnLoc.hasValue()) {
    return {None, topLevel};
  }

  // Emit top-level cleanups into the epilog block.
  assert(!Cleanups.hasAnyActiveCleanups(getCleanupsDepth(),
                                        ReturnDest.getDepth()) &&
         "emitting epilog in wrong scope");

  auto cleanupLoc = CleanupLocation::get(topLevel);
  Cleanups.emitCleanupsForReturn(cleanupLoc);

  // Build the return value.  We don't do this if there are no direct
  // results; this can happen for void functions, but also happens when
  // prepareEpilog was asked to not add result arguments to the epilog
  // block.
  SILValue returnValue;
  if (!directResults.empty()) {
    assert(directResults.size() == F.getConventions().getNumDirectSILResults());
    returnValue = buildReturnValue(*this, topLevel, directResults);
  }

  return {returnValue, *returnLoc};
}

SILLocation SILGenFunction::
emitEpilog(SILLocation TopLevel, bool UsesCustomEpilog) {
  Optional<SILValue> maybeReturnValue;
  SILLocation returnLoc(TopLevel);
  std::tie(maybeReturnValue, returnLoc) = emitEpilogBB(TopLevel);

  SILBasicBlock *ResultBB = nullptr;

  if (!maybeReturnValue) {
    // Nothing to do.
  } else if (UsesCustomEpilog) {
    // If the epilog is reachable, and the caller provided an epilog, just
    // remember the block so the caller can continue it.
    ResultBB = B.getInsertionBB();
    assert(ResultBB && "Didn't have an epilog block?");
    B.clearInsertionPoint();
  } else {
    // Otherwise, if the epilog block is reachable, return the return value.
    SILValue returnValue = *maybeReturnValue;

    // Return () if no return value was given.
    if (!returnValue)
      returnValue = emitEmptyTuple(CleanupLocation::get(TopLevel));

    B.createReturn(returnLoc, returnValue);
  }

  emitRethrowEpilog(TopLevel);

  if (ResultBB)
    B.setInsertionPoint(ResultBB);

  return returnLoc;
}

void SILGenFunction::emitRethrowEpilog(SILLocation topLevel) {
  assert(!B.hasValidInsertionPoint());

  // If we don't have a rethrow destination, we're done.
  if (!ThrowDest.isValid())
    return;

  // If the rethrow destination isn't used, we're done.
  SILBasicBlock *rethrowBB = ThrowDest.getBlock();
  if (rethrowBB->pred_empty()) {
    ThrowDest = JumpDest::invalid();
    eraseBasicBlock(rethrowBB);
    return;
  }

  SILLocation throwLoc = topLevel;
  SILValue exn = rethrowBB->args_begin()[0];
  bool reposition = true;

  // If the rethrow destination has a single branch predecessor,
  // consider emitting the rethrow into it.
  SILBasicBlock *predBB = *rethrowBB->pred_begin();
  if (std::next(rethrowBB->pred_begin()) == rethrowBB->pred_end()) {
    if (auto branch = dyn_cast<BranchInst>(predBB->getTerminator())) {
      assert(branch->getArgs().size() == 1);

      // Save the location and operand information from the branch,
      // then destroy it.
      throwLoc = branch->getLoc();
      exn = branch->getArgs()[0];
      predBB->erase(branch);

      // Erase the rethrow block.
      eraseBasicBlock(rethrowBB);
      rethrowBB = predBB;
      reposition = false;
    }
  }

  // Reposition the rethrow block to the end of the postmatter section
  // unless we're emitting into a single predecessor.
  if (reposition) {
    B.moveBlockTo(rethrowBB, F.end());
  }

  B.setInsertionPoint(rethrowBB);
  Cleanups.emitCleanupsForReturn(ThrowDest.getCleanupLocation());

  B.createThrow(throwLoc, exn);

  ThrowDest = JumpDest::invalid();
}
<|endoftext|>


<commit_before>/*
 * Copyright 2007-2019 Content Management AG
 * All rights reserved.
 *
 * author: Max Kellermann <mk@cm4all.com>
 *
 * 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.
 *
 * 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
 * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#pragma once

#include "util/Compiler.h"

#include <utility>

struct AllocatorPtr;
struct Stopwatch;
class SocketAddress;
class SocketDescriptor;

#ifdef ENABLE_STOPWATCH

class StopwatchPtr {
    Stopwatch *stopwatch = nullptr;

public:
    StopwatchPtr() = default;
    StopwatchPtr(std::nullptr_t) noexcept {}

    StopwatchPtr(AllocatorPtr alloc, const char *name,
                 const char *suffix=nullptr) noexcept;

    StopwatchPtr(AllocatorPtr alloc, SocketAddress address,
                 const char *suffix=nullptr) noexcept;

    StopwatchPtr(AllocatorPtr alloc, SocketDescriptor fd,
                 const char *suffix=nullptr) noexcept;

    StopwatchPtr(StopwatchPtr &&src) noexcept
        :stopwatch(std::exchange(src.stopwatch, nullptr)) {}

    ~StopwatchPtr() noexcept {
        if (stopwatch != nullptr)
            Destruct(*stopwatch);
    }

    operator bool() const noexcept {
        return stopwatch != nullptr;
    }

    void RecordEvent(const char *name) const noexcept;

private:
    static void Destruct(Stopwatch &stopwatch) noexcept;
};

void
stopwatch_enable();

gcc_const
bool
stopwatch_is_enabled();

#else

#include "AllocatorPtr.hxx"
#include "net/SocketAddress.hxx"
#include "net/SocketDescriptor.hxx"

class StopwatchPtr {
public:
    StopwatchPtr() = default;
    StopwatchPtr(std::nullptr_t) noexcept {}

    template<typename N>
    StopwatchPtr(AllocatorPtr, N &&, const char *=nullptr) noexcept {}

    operator bool() const noexcept {
        return false;
    }

    void RecordEvent(const char *) const noexcept {}
    void Dump() const noexcept {}
    void Finish(const char *) const noexcept {}
};

static inline void
stopwatch_enable()
{
}

static inline bool
stopwatch_is_enabled()
{
    return false;
}

#endif
<commit_msg>stopwatch: fix syntax ambiguity<commit_after>/*
 * Copyright 2007-2019 Content Management AG
 * All rights reserved.
 *
 * author: Max Kellermann <mk@cm4all.com>
 *
 * 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.
 *
 * 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
 * FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#pragma once

#include "util/Compiler.h"

#include <utility>

struct AllocatorPtr;
struct Stopwatch;
class SocketAddress;
class SocketDescriptor;

#ifdef ENABLE_STOPWATCH

class StopwatchPtr {
    Stopwatch *stopwatch = nullptr;

public:
    StopwatchPtr() = default;
    StopwatchPtr(std::nullptr_t) noexcept {}

    StopwatchPtr(AllocatorPtr alloc, const char *name,
                 const char *suffix=nullptr) noexcept;

    StopwatchPtr(AllocatorPtr alloc, SocketAddress address,
                 const char *suffix=nullptr) noexcept;

    StopwatchPtr(AllocatorPtr alloc, SocketDescriptor fd,
                 const char *suffix=nullptr) noexcept;

    StopwatchPtr(StopwatchPtr &&src) noexcept
        :stopwatch(std::exchange(src.stopwatch, nullptr)) {}

    ~StopwatchPtr() noexcept {
        if (stopwatch != nullptr)
            Destruct(*stopwatch);
    }

    operator bool() const noexcept {
        return stopwatch != nullptr;
    }

    void RecordEvent(const char *name) const noexcept;

private:
    static void Destruct(Stopwatch &stopwatch) noexcept;
};

void
stopwatch_enable();

gcc_const
bool
stopwatch_is_enabled();

#else

#include "AllocatorPtr.hxx"
#include "net/SocketAddress.hxx"
#include "net/SocketDescriptor.hxx"

class StopwatchPtr {
public:
    StopwatchPtr() = default;
    StopwatchPtr(std::nullptr_t) noexcept {}

    template<typename N>
    StopwatchPtr(AllocatorPtr, N &&, const char * =nullptr) noexcept {}

    operator bool() const noexcept {
        return false;
    }

    void RecordEvent(const char *) const noexcept {}
    void Dump() const noexcept {}
    void Finish(const char *) const noexcept {}
};

static inline void
stopwatch_enable()
{
}

static inline bool
stopwatch_is_enabled()
{
    return false;
}

#endif
<|endoftext|>