<commit_before>#include "bitcrypto/KeyGenerator.hpp"

namespace BitCrypto{

KeyGenerator::KeyGenerator() :
    _secretGenerator(getContext()),
    _pubKeyGenerator(getContext())
{}

KeyGenerator::KeyGenerator(const Secp256k1ContextPtr &context):
    Secp256k1Handler(context),
    _secretGenerator(getContext()),
    _pubKeyGenerator(getContext())
{}

KeyPair KeyGenerator::generate()
{
    Secret secret = _secretGenerator.generate();
    return KeyPair(secret, _pubKeyGenerator.createFromSecret(secret));
}

KeyPair KeyGenerator::generate(const Data &entropy)
{
    Secret secret = _secretGenerator.generate(entropy);
    return KeyPair(secret, _pubKeyGenerator.createFromSecret(secret));
}

KeyPair KeyGenerator::generate(const char *entropy)
{
    Secret secret = _secretGenerator.generate(entropy);
    return KeyPair(secret, _pubKeyGenerator.createFromSecret(secret));
}

}
<commit_msg>retrying to create key pair<commit_after>#include "bitcrypto/KeyGenerator.hpp"

namespace BitCrypto{

KeyGenerator::KeyGenerator() :
    _secretGenerator(getContext()),
    _pubKeyGenerator(getContext())
{}

KeyGenerator::KeyGenerator(const Secp256k1ContextPtr &context):
    Secp256k1Handler(context),
    _secretGenerator(getContext()),
    _pubKeyGenerator(getContext())
{}

KeyPair KeyGenerator::generate()
{
    for(int i=0; i<100; i++)
    {
        try
        {
            Secret secret = _secretGenerator.generate();
            return KeyPair(secret, _pubKeyGenerator.createFromSecret(secret));
        }
        catch(const std::runtime_error &)
        {}
    }
    throw std::runtime_error("failed to generate keypair");
}

KeyPair KeyGenerator::generate(const Data &entropy)
{
    Secret secret = _secretGenerator.generate(entropy);
    return KeyPair(secret, _pubKeyGenerator.createFromSecret(secret));
}

KeyPair KeyGenerator::generate(const char *entropy)
{
    Secret secret = _secretGenerator.generate(entropy);
    return KeyPair(secret, _pubKeyGenerator.createFromSecret(secret));
}

}
<|endoftext|>


<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2015 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

// mapnik
#include <mapnik/json/error_handler.hpp>
#include <mapnik/json/feature_collection_grammar.hpp>

// spirit::qi
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>

namespace mapnik { namespace json {

template <typename Iterator, typename FeatureType, typename FeatureCallback, typename ErrorHandler>
feature_collection_grammar<Iterator,FeatureType, FeatureCallback,ErrorHandler>::feature_collection_grammar(mapnik::transcoder const& tr)
        : feature_collection_grammar::base_type(start,"start"),
          feature_g(tr)
{
        qi::lit_type lit;
        qi::eps_type eps;
        qi::_1_type _1;
        qi::_2_type _2;
        qi::_3_type _3;
        qi::_4_type _4;
        qi::_a_type _a;
        qi::_r1_type _r1;
        qi::_r2_type _r2;
        qi::_r3_type _r3;
        using phoenix::construct;
        using phoenix::new_;
        using phoenix::val;
        using qi::on_error;
        using qi::fail;
        start = feature_collection(_r1, _r2, _r3)
            ;

        feature_collection = lit('{') >> (type | features(_r1, _r2, _r3) | feature_g.json_.key_value) % lit(',') >> lit('}')
            ;

        type = lit("\"type\"") >> lit(':') >> lit("\"FeatureCollection\"")
            ;

        features = lit("\"features\"")
            >> lit(':')
            >> lit('[')
            >> -(feature(_r1, _r2, _r3) [_r2 +=1] % lit(','))
            >> lit(']')
            ;

        feature = eps[_a = phoenix::construct<mapnik::feature_ptr>(new_<mapnik::feature_impl>(_r1, _r2))]
            >> feature_g(*_a)[on_feature(_r3,_a)]
            ;

        start.name("start");
        type.name("type");
        features.name("features");
        feature.name("feature");
        feature_g.name("feature-grammar");
        on_error<fail>(feature_collection, error_handler(_1, _2, _3, _4));
}

template <typename Iterator, typename FeatureType, typename FeatureCallback, typename ErrorHandler>
feature_grammar_callback<Iterator,FeatureType, FeatureCallback,ErrorHandler>::feature_grammar_callback(mapnik::transcoder const& tr)
    : feature_grammar_callback::base_type(start,"start"),
      feature_g(tr)
{
        qi::lit_type lit;
        qi::eps_type eps;
        qi::_1_type _1;
        qi::_2_type _2;
        qi::_3_type _3;
        qi::_4_type _4;
        qi::_a_type _a;
        qi::_r1_type _r1;
        qi::_r2_type _r2;
        qi::_r3_type _r3;
        using phoenix::construct;
        using phoenix::new_;
        using phoenix::val;
        using qi::on_error;
        using qi::fail;
        start = feature_from_geometry(_r1, _r2, _r3) | feature(_r1, _r2, _r3)
            ;

        feature = eps[_a = phoenix::construct<mapnik::feature_ptr>(new_<mapnik::feature_impl>(_r1, _r2))]
            >> feature_g(*_a)[on_feature(_r3,_a)]
            ;

        feature_from_geometry =
            eps[_a = phoenix::construct<mapnik::feature_ptr>(new_<mapnik::feature_impl>(_r1, _r2))]
            >> geometry_g[set_geometry(*_a, _1)] [on_feature(_r3, _a)]
            ;

        start.name("start");
        feature.name("feature");
        feature_from_geometry.name("feature-from-geometry");
        feature_g.name("feature-grammar");
        geometry_g.name("geometry-grammar");
        on_error<fail>(feature, error_handler(_1, _2, _3, _4));
}

}}
<commit_msg>GeoJSON - refactor FeatureCollection grammar to restore empty `features` condition (#3167)<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2015 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

// mapnik
#include <mapnik/json/error_handler.hpp>
#include <mapnik/json/feature_collection_grammar.hpp>

// spirit::qi
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/phoenix.hpp>

namespace mapnik { namespace json {

template <typename Iterator, typename FeatureType, typename FeatureCallback, typename ErrorHandler>
feature_collection_grammar<Iterator,FeatureType, FeatureCallback,ErrorHandler>::feature_collection_grammar(mapnik::transcoder const& tr)
        : feature_collection_grammar::base_type(start,"start"),
          feature_g(tr)
{
        qi::lit_type lit;
        qi::eps_type eps;
        qi::_1_type _1;
        qi::_2_type _2;
        qi::_3_type _3;
        qi::_4_type _4;
        qi::_a_type _a;
        qi::_r1_type _r1;
        qi::_r2_type _r2;
        qi::_r3_type _r3;
        using phoenix::construct;
        using phoenix::new_;
        using phoenix::val;
        using qi::on_error;
        using qi::fail;
        start = feature_collection(_r1, _r2, _r3)
            ;

        feature_collection = lit('{') > (type | features(_r1, _r2, _r3) | feature_g.json_.key_value) % lit(',') > lit('}')
            ;

        type = lit("\"type\"") > lit(':') > lit("\"FeatureCollection\"")
            ;

        features = lit("\"features\"")
            > lit(':') > lit('[') >
            ( lit(']') | ((feature(_r1, _r2, _r3) [_r2 +=1] % lit(',')) > lit(']')))
            ;

        feature = eps[_a = phoenix::construct<mapnik::feature_ptr>(new_<mapnik::feature_impl>(_r1, _r2))]
            > feature_g(*_a)[on_feature(_r3,_a)]
            ;

        start.name("start");
        feature_collection.name("FeatureCollection");
        type.name("type");
        features.name("features");
        feature.name("feature");
        feature_g.name("feature-grammar");
        on_error<fail>(feature_collection, error_handler(_1, _2, _3, _4));
}

template <typename Iterator, typename FeatureType, typename FeatureCallback, typename ErrorHandler>
feature_grammar_callback<Iterator,FeatureType, FeatureCallback,ErrorHandler>::feature_grammar_callback(mapnik::transcoder const& tr)
    : feature_grammar_callback::base_type(start,"start"),
      feature_g(tr)
{
        qi::lit_type lit;
        qi::eps_type eps;
        qi::_1_type _1;
        qi::_2_type _2;
        qi::_3_type _3;
        qi::_4_type _4;
        qi::_a_type _a;
        qi::_r1_type _r1;
        qi::_r2_type _r2;
        qi::_r3_type _r3;
        using phoenix::construct;
        using phoenix::new_;
        using phoenix::val;
        using qi::on_error;
        using qi::fail;
        start = feature_from_geometry(_r1, _r2, _r3) | feature(_r1, _r2, _r3)
            ;

        feature = eps[_a = phoenix::construct<mapnik::feature_ptr>(new_<mapnik::feature_impl>(_r1, _r2))]
            >> feature_g(*_a)[on_feature(_r3,_a)]
            ;

        feature_from_geometry =
            eps[_a = phoenix::construct<mapnik::feature_ptr>(new_<mapnik::feature_impl>(_r1, _r2))]
            >> geometry_g[set_geometry(*_a, _1)] [on_feature(_r3, _a)]
            ;

        start.name("start");
        feature.name("feature");
        feature_from_geometry.name("feature-from-geometry");
        feature_g.name("feature-grammar");
        geometry_g.name("geometry-grammar");
        on_error<fail>(feature, error_handler(_1, _2, _3, _4));
}

}}
<|endoftext|>


<commit_before>//   Copyright 2015 Patrick Putnam
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
#ifndef CLOTHO_QTL_ALLELE_HPP_
#define CLOTHO_QTL_ALLELE_HPP_

#include "clotho/data_spaces/allele_space/neutral_allele.hpp"
#include "clotho/data_spaces/growable2D.hpp"
#include "clotho/data_spaces/trait_helper_of.hpp"

#include "clotho/utility/state_object.hpp"
#include "clotho/utility/log_helper.hpp"

#include <algorithm>

namespace clotho {
namespace genetics {

template < class PositionType, class WeightType >
class qtl_allele_vectorized : public neutral_allele_vectorized< PositionType >, public growable2D {
public:
    typedef neutral_allele_vectorized< PositionType > base_type;
    typedef qtl_allele_vectorized< PositionType, WeightType > self_type;

    typedef WeightType                  weight_type;
    typedef std::vector< WeightType >   trait_type;

    typedef weight_type *               weight_pointer;

    friend class clotho::utility::state_getter< self_type >;

    class weight_iterator {
    public:
        weight_iterator( weight_type * ptr, size_t size ) :
            m_ptr( ptr )
            , m_size( size ) {}

        weight_iterator( const weight_iterator & other ) :
            m_ptr( other.m_ptr )
            , m_size( other.m_size )
        {}

        bool hasNext() const {
            return (m_size > 0);
        }

        weight_type next() {
            assert( m_size > 0 );
            weight_type w = *m_ptr++;
            --m_size;

            return w;
        }

        virtual ~weight_iterator() {}
    protected:
        weight_type * m_ptr;
        size_t      m_size;
    };

    typedef weight_iterator     trait_iterator;

    qtl_allele_vectorized( size_t rows = 0, size_t columns = 0 ) :
        m_weights(NULL)
        , m_rows(0)
        , m_columns(0)
        , m_size(0)
    {
        this->resize(rows, columns);
    }

    trait_iterator getTraitIterator( size_t allele_idx ) const {
        assert( 0 <= allele_idx && allele_idx < m_rows );
        return trait_iterator( m_weights + allele_idx * m_columns, m_columns );
    }

    void updateTraitWeight( size_t allele_idx, size_t trait_idx, weight_type w ) {
        assert( 0 <= allele_idx && allele_idx < m_rows );
        assert( 0 <= trait_idx && trait_idx < m_columns );

        m_weights[ allele_idx * m_columns + trait_idx ] = w;
    }

    virtual size_t grow( size_t alleles ) {
        size_t t = trait_count();
        if( t == 0 ) {
            t += 1;
        }
        this->resize( alleles, t );
        return m_rows;
    }

    virtual size_t grow( size_t alleles, size_t traits ) {
        this->resize( alleles, traits );

        return m_rows;
    }

    trait_type  makeEmptyTrait() {
        return trait_type( m_columns, 0.0);
    }

    size_t allele_count() const {
        return m_rows;
    }

    size_t trait_count() const {
        return m_columns;
    }

    size_t allocated_size() const {
        return m_size;
    }

    void inherit( self_type & parent ) {
        std::copy( parent.position_begin(), parent.position_end(), this->position_begin() );
        std::copy( parent.neutral_begin(), parent.neutral_end(), this->m_neutral.begin() );

        size_t t = trait_count();
        size_t ot = parent.trait_count();

        size_t a = allele_count();
        size_t oa = parent.allele_count();

        assert( oa <= a );

        size_t i = 0, T = ((t < ot) ? t : ot );
        while( i < T ) {
            memcpy( this->m_weights + i * a, parent.m_weights + i * oa, oa * sizeof( weight_type ) );
            ++i;
        }

    }

    weight_pointer begin_trait_weight( size_t idx ) {
        if(!( 0 <= idx && idx < allele_count()) ) {
            std::cerr << "Trait out of range: " << idx << " [ " << allele_count() << " ]" << std::endl;
        }
        assert( 0 <= idx && idx < allele_count() );

        return m_weights + idx * trait_count();
    }

    weight_pointer end_trait_weight( size_t idx ) {
        assert( 0 <= idx && idx < allele_count() );

        return m_weights + (idx + 1) * trait_count();
    }

    void push_back( self_type & other, size_t idx ) {
        size_t  acount = allele_count();
        size_t  tcount = trait_count();

        if( tcount < other.trait_count() ) {
            tcount = other.trait_count();
        }

        this->resize( acount + 1, tcount );

        this->setPositionAt( acount, other.getPositionAt(idx) );
        this->setNeutralAt( acount, other.getNeutralAt(idx) );

        weight_type * t = other.m_weights + idx * tcount;
        weight_type * s = this->m_weights + acount * tcount;

        memcpy( s, t, tcount * sizeof(weight_type) );
    }

    virtual ~qtl_allele_vectorized() {
        if( m_weights != NULL ) {
            delete [] m_weights;
        }
    }

protected:

    virtual void resize( size_t rows, size_t columns ) {
        base_type::resize( rows );

        rows = base_type::size();

        size_t new_size = rows * columns;

        assert( 0 <= new_size );

        if( m_size < new_size ) {
            // growing trait space
            weight_type * tmp = new weight_type[ new_size ];

            if( m_weights != NULL ) {
                memcpy( tmp, m_weights, m_size * sizeof( weight_type ) );
                delete [] m_weights;
            }

            m_weights = tmp;

            m_size = new_size;
        }

        m_columns = columns;
        m_rows = rows;
    }

    virtual void resize( size_t rows ) {
        this->resize( rows, m_columns );
    }

    weight_pointer  m_weights;
    size_t          m_rows, m_columns, m_size;
};

template < class PositionType, class WeightType >
struct trait_helper_of< qtl_allele_vectorized< PositionType, WeightType > > {
    typedef qtl_allele_vectorized< PositionType, WeightType > allele_type;
    typedef typename allele_type::trait_type type;

    static type makeEmptyTrait( size_t N ) {
        type r = type( N, 0.0);
        return r;
    }

    static void resetTrait( type & trait ) {
        size_t i = 0;
        while( i < trait.size() ) {
            trait[i++] = 0.0;
        }
    }

};

}   // namespace genetics
}   // namespace clotho

namespace clotho {
namespace utility {

template < class PositionType, class WeightType >
struct state_getter< clotho::genetics::qtl_allele_vectorized< PositionType, WeightType > > {
    typedef clotho::genetics::qtl_allele_vectorized< PositionType, WeightType > object_type;

    void operator()( boost::property_tree::ptree & s, object_type & obj ) {
        typedef typename object_type::trait_iterator    iterator;
        typedef typename object_type::weight_type       weight_type;

        size_t all_count = obj.allele_count();
        size_t i = 0;
        while( i < all_count ) {
            boost::property_tree::ptree all;
            all.put( "position", obj.getPositionAt(i) );
            all.put( "neutral", obj.getNeutralAt(i) );

            boost::property_tree::ptree t;
            iterator it = obj.getTraitIterator( i );
            while( it.hasNext() ) {
                weight_type w = it.next();
                clotho::utility::add_value_array( t, w );
            }
            all.put_child( "trait", t );

            s.push_back( std::make_pair("", all ) );
            ++i;
        }

    }
};

}   // namespace utility
}   // namespace clotho
#endif  // CLOTHO_QTL_ALLELE_HPP_
<commit_msg>removed debugging code<commit_after>//   Copyright 2015 Patrick Putnam
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
#ifndef CLOTHO_QTL_ALLELE_HPP_
#define CLOTHO_QTL_ALLELE_HPP_

#include "clotho/data_spaces/allele_space/neutral_allele.hpp"
#include "clotho/data_spaces/growable2D.hpp"
#include "clotho/data_spaces/trait_helper_of.hpp"

#include "clotho/utility/state_object.hpp"
#include "clotho/utility/log_helper.hpp"

#include <algorithm>

namespace clotho {
namespace genetics {

template < class PositionType, class WeightType >
class qtl_allele_vectorized : public neutral_allele_vectorized< PositionType >, public growable2D {
public:
    typedef neutral_allele_vectorized< PositionType > base_type;
    typedef qtl_allele_vectorized< PositionType, WeightType > self_type;

    typedef WeightType                  weight_type;
    typedef std::vector< WeightType >   trait_type;

    typedef weight_type *               weight_pointer;

    friend class clotho::utility::state_getter< self_type >;

    class weight_iterator {
    public:
        weight_iterator( weight_type * ptr, size_t size ) :
            m_ptr( ptr )
            , m_size( size ) {}

        weight_iterator( const weight_iterator & other ) :
            m_ptr( other.m_ptr )
            , m_size( other.m_size )
        {}

        bool hasNext() const {
            return (m_size > 0);
        }

        weight_type next() {
            assert( m_size > 0 );
            weight_type w = *m_ptr++;
            --m_size;

            return w;
        }

        virtual ~weight_iterator() {}
    protected:
        weight_type * m_ptr;
        size_t      m_size;
    };

    typedef weight_iterator     trait_iterator;

    qtl_allele_vectorized( size_t rows = 0, size_t columns = 0 ) :
        m_weights(NULL)
        , m_rows(0)
        , m_columns(0)
        , m_size(0)
    {
        this->resize(rows, columns);
    }

    trait_iterator getTraitIterator( size_t allele_idx ) const {
        assert( 0 <= allele_idx && allele_idx < m_rows );
        return trait_iterator( m_weights + allele_idx * m_columns, m_columns );
    }

    void updateTraitWeight( size_t allele_idx, size_t trait_idx, weight_type w ) {
        assert( 0 <= allele_idx && allele_idx < m_rows );
        assert( 0 <= trait_idx && trait_idx < m_columns );

        m_weights[ allele_idx * m_columns + trait_idx ] = w;
    }

    virtual size_t grow( size_t alleles ) {
        size_t t = trait_count();
        if( t == 0 ) {
            t += 1;
        }
        this->resize( alleles, t );
        return m_rows;
    }

    virtual size_t grow( size_t alleles, size_t traits ) {
        this->resize( alleles, traits );

        return m_rows;
    }

    trait_type  makeEmptyTrait() {
        return trait_type( m_columns, 0.0);
    }

    size_t allele_count() const {
        return m_rows;
    }

    size_t trait_count() const {
        return m_columns;
    }

    size_t allocated_size() const {
        return m_size;
    }

    void inherit( self_type & parent ) {
        std::copy( parent.position_begin(), parent.position_end(), this->position_begin() );
        std::copy( parent.neutral_begin(), parent.neutral_end(), this->m_neutral.begin() );

        size_t t = trait_count();
        size_t ot = parent.trait_count();

        size_t a = allele_count();
        size_t oa = parent.allele_count();

        assert( oa <= a );

        size_t i = 0, T = ((t < ot) ? t : ot );
        while( i < T ) {
            memcpy( this->m_weights + i * a, parent.m_weights + i * oa, oa * sizeof( weight_type ) );
            ++i;
        }

    }

    weight_pointer begin_trait_weight( size_t idx ) {
        assert( 0 <= idx && idx < allele_count() );

        return m_weights + idx * trait_count();
    }

    weight_pointer end_trait_weight( size_t idx ) {
        assert( 0 <= idx && idx < allele_count() );

        return m_weights + (idx + 1) * trait_count();
    }

    void push_back( self_type & other, size_t idx ) {
        size_t  acount = allele_count();
        size_t  tcount = trait_count();

        if( tcount < other.trait_count() ) {
            tcount = other.trait_count();
        }

        this->resize( acount + 1, tcount );

        this->setPositionAt( acount, other.getPositionAt(idx) );
        this->setNeutralAt( acount, other.getNeutralAt(idx) );

        weight_type * t = other.m_weights + idx * tcount;
        weight_type * s = this->m_weights + acount * tcount;

        memcpy( s, t, tcount * sizeof(weight_type) );
    }

    virtual ~qtl_allele_vectorized() {
        if( m_weights != NULL ) {
            delete [] m_weights;
        }
    }

protected:

    virtual void resize( size_t rows, size_t columns ) {
        base_type::resize( rows );

        rows = base_type::size();

        size_t new_size = rows * columns;

        assert( 0 <= new_size );

        if( m_size < new_size ) {
            // growing trait space
            weight_type * tmp = new weight_type[ new_size ];

            if( m_weights != NULL ) {
                memcpy( tmp, m_weights, m_size * sizeof( weight_type ) );
                delete [] m_weights;
            }

            m_weights = tmp;

            m_size = new_size;
        }

        m_columns = columns;
        m_rows = rows;
    }

    virtual void resize( size_t rows ) {
        this->resize( rows, m_columns );
    }

    weight_pointer  m_weights;
    size_t          m_rows, m_columns, m_size;
};

template < class PositionType, class WeightType >
struct trait_helper_of< qtl_allele_vectorized< PositionType, WeightType > > {
    typedef qtl_allele_vectorized< PositionType, WeightType > allele_type;
    typedef typename allele_type::trait_type type;

    static type makeEmptyTrait( size_t N ) {
        type r = type( N, 0.0);
        return r;
    }

    static void resetTrait( type & trait ) {
        size_t i = 0;
        while( i < trait.size() ) {
            trait[i++] = 0.0;
        }
    }

};

}   // namespace genetics
}   // namespace clotho

namespace clotho {
namespace utility {

template < class PositionType, class WeightType >
struct state_getter< clotho::genetics::qtl_allele_vectorized< PositionType, WeightType > > {
    typedef clotho::genetics::qtl_allele_vectorized< PositionType, WeightType > object_type;

    void operator()( boost::property_tree::ptree & s, object_type & obj ) {
        typedef typename object_type::trait_iterator    iterator;
        typedef typename object_type::weight_type       weight_type;

        size_t all_count = obj.allele_count();
        size_t i = 0;
        while( i < all_count ) {
            boost::property_tree::ptree all;
            all.put( "position", obj.getPositionAt(i) );
            all.put( "neutral", obj.getNeutralAt(i) );

            boost::property_tree::ptree t;
            iterator it = obj.getTraitIterator( i );
            while( it.hasNext() ) {
                weight_type w = it.next();
                clotho::utility::add_value_array( t, w );
            }
            all.put_child( "trait", t );

            s.push_back( std::make_pair("", all ) );
            ++i;
        }

    }
};

}   // namespace utility
}   // namespace clotho
#endif  // CLOTHO_QTL_ALLELE_HPP_
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2018 ScyllaDB
 */

/*
 * This file is part of Scylla.
 *
 * Scylla is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Scylla is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "database.hh"
#include "db/system_keyspace.hh"
#include "db/timeout_clock.hh"
#include "dht/i_partitioner.hh"
#include "flat_mutation_reader.hh"
#include "mutation_fragment.hh"
#include "mutation_reader.hh"
#include "query-request.hh"
#include "schema.hh"
#include "tracing/tracing.hh"

#include <boost/range/iterator_range.hpp>

#include <iterator>
#include <memory>

namespace db::view {

// Allows a user to query the views_builds_in_progress system table
// in terms of the scylla_views_builds_in_progress one, which is
// a superset of the former. When querying, we don't have to adjust
// the clustering key, but we have to adjust the requested regular
// columns. When reading the results from the scylla_views_builds_in_progress
// table, we adjust the clustering key (we shed the cpu_id column) and map
// back the regular columns.
class build_progress_virtual_reader {
    database& _db;

    struct build_progress_reader : flat_mutation_reader::impl {
        column_id _scylla_next_token_col;
        column_id _scylla_generation_number_col;
        column_id _legacy_last_token_col;
        column_id _legacy_generation_number_col;
        const query::partition_slice& _legacy_slice;
        query::partition_slice _slice;
        flat_mutation_reader _underlying;

        build_progress_reader(
                schema_ptr legacy_schema,
                column_family& scylla_views_build_progress,
                const dht::partition_range& range,
                const query::partition_slice& slice,
                const io_priority_class& pc,
                tracing::trace_state_ptr trace_state,
                streamed_mutation::forwarding fwd,
                mutation_reader::forwarding fwd_mr)
                : flat_mutation_reader::impl(std::move(legacy_schema))
                , _scylla_next_token_col(scylla_views_build_progress.schema()->get_column_definition("next_token")->id)
                , _scylla_generation_number_col(scylla_views_build_progress.schema()->get_column_definition("generation_number")->id)
                , _legacy_last_token_col(_schema->get_column_definition("last_token")->id)
                , _legacy_generation_number_col(_schema->get_column_definition("generation_number")->id)
                , _legacy_slice(slice)
                , _slice(adjust_partition_slice())
                , _underlying(scylla_views_build_progress.make_reader(
                        scylla_views_build_progress.schema(),
                        range,
                        slice,
                        pc,
                        std::move(trace_state),
                        fwd,
                        fwd_mr)) {
        }

        const schema& underlying_schema() const {
            return *_underlying.schema();
        }

        query::partition_slice adjust_partition_slice() {
            auto slice = _legacy_slice;
            query::column_id_vector adjusted_columns;
            for (auto col_id : slice.regular_columns) {
                if (col_id == _legacy_last_token_col) {
                    adjusted_columns.push_back(_scylla_next_token_col);
                } else if (col_id == _legacy_generation_number_col) {
                    adjusted_columns.push_back(_scylla_generation_number_col);
                }
            }
            slice.regular_columns = std::move(adjusted_columns);
            return slice;
        }

        clustering_key adjust_ckey(clustering_key& underlying_ck) {
            if (!underlying_ck.is_full(underlying_schema())) {
                return std::move(underlying_ck);
            }
            // Drop the cpu_id from the clustering key
            auto end = underlying_ck.begin(underlying_schema());
            std::advance(end, underlying_schema().clustering_key_size() - 1);
            auto r = boost::make_iterator_range(underlying_ck.begin(underlying_schema()), std::move(end));
            return clustering_key_prefix::from_exploded(r);
        }

        virtual future<> fill_buffer(db::timeout_clock::time_point timeout) override {
            return _underlying.fill_buffer(timeout).then([this] {
                _end_of_stream = _underlying.is_end_of_stream();
                while (!_underlying.is_buffer_empty()) {
                    auto mf = _underlying.pop_mutation_fragment();
                    if (mf.is_clustering_row()) {
                        auto scylla_in_progress_row = std::move(mf).as_clustering_row();
                        auto legacy_in_progress_row = row();
                        // Drop the first_token from the regular columns
                        scylla_in_progress_row.cells().for_each_cell([&, this] (column_id id, atomic_cell_or_collection& c) {
                            if (id == _scylla_next_token_col) {
                                legacy_in_progress_row.append_cell(_legacy_last_token_col, std::move(c));
                            } else if (id == _scylla_generation_number_col) {
                                legacy_in_progress_row.append_cell(_legacy_generation_number_col, std::move(c));
                            }
                        });
                        mf = clustering_row(
                                adjust_ckey(scylla_in_progress_row.key()),
                                std::move(scylla_in_progress_row.tomb()),
                                std::move(scylla_in_progress_row.marker()),
                                std::move(legacy_in_progress_row));
                    } else if (mf.is_range_tombstone()) {
                        auto scylla_in_progress_rt = std::move(mf).as_range_tombstone();
                        mf = range_tombstone(
                                adjust_ckey(scylla_in_progress_rt.start),
                                scylla_in_progress_rt.start_kind,
                                adjust_ckey(scylla_in_progress_rt.end),
                                scylla_in_progress_rt.end_kind,
                                scylla_in_progress_rt.tomb);
                    }
                    push_mutation_fragment(std::move(mf));
                }
            });
        }

        virtual void next_partition() override {
            _end_of_stream = false;
            clear_buffer_to_next_partition();
            if (is_buffer_empty()) {
                _underlying.next_partition();
            }
        }

        virtual future<> fast_forward_to(const dht::partition_range& pr, db::timeout_clock::time_point timeout) override {
            clear_buffer();
            _end_of_stream = false;
            return _underlying.fast_forward_to(pr, timeout);
        }

        virtual future<> fast_forward_to(position_range range, db::timeout_clock::time_point timeout) override {
            forward_buffer_to(range.start());
            _end_of_stream = false;
            return _underlying.fast_forward_to(std::move(range), timeout);
        }
    };

public:
    build_progress_virtual_reader(database& db)
            : _db(db) {
    }

    flat_mutation_reader operator()(
            schema_ptr s,
            const dht::partition_range& range,
            const query::partition_slice& slice,
            const io_priority_class& pc,
            tracing::trace_state_ptr trace_state,
            streamed_mutation::forwarding fwd,
            mutation_reader::forwarding fwd_mr) {
        return flat_mutation_reader(std::make_unique<build_progress_reader>(
                std::move(s),
                _db.find_column_family(s->ks_name(), system_keyspace::v3::SCYLLA_VIEWS_BUILDS_IN_PROGRESS),
                range,
                slice,
                pc,
                std::move(trace_state),
                fwd,
                fwd_mr));
    }
};

}<commit_msg>view: ignore duplicated key entries in progress virtual reader<commit_after>/*
 * Copyright (C) 2018 ScyllaDB
 */

/*
 * This file is part of Scylla.
 *
 * Scylla is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Scylla is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Scylla.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "database.hh"
#include "db/system_keyspace.hh"
#include "db/timeout_clock.hh"
#include "dht/i_partitioner.hh"
#include "flat_mutation_reader.hh"
#include "mutation_fragment.hh"
#include "mutation_reader.hh"
#include "query-request.hh"
#include "schema.hh"
#include "tracing/tracing.hh"

#include <boost/range/iterator_range.hpp>

#include <iterator>
#include <memory>

namespace db::view {

// Allows a user to query the views_builds_in_progress system table
// in terms of the scylla_views_builds_in_progress one, which is
// a superset of the former. When querying, we don't have to adjust
// the clustering key, but we have to adjust the requested regular
// columns. When reading the results from the scylla_views_builds_in_progress
// table, we adjust the clustering key (we shed the cpu_id column) and map
// back the regular columns.
// Since mutation fragment consumers expect clustering_row fragments
// not to be duplicated for given primary key, previous clustering key
// is stored between mutation fragments. If the clustering key becomes
// the same as the previous one (as a result of trimming cpu_id),
// the duplicated fragment is ignored.
class build_progress_virtual_reader {
    database& _db;

    struct build_progress_reader : flat_mutation_reader::impl {
        column_id _scylla_next_token_col;
        column_id _scylla_generation_number_col;
        column_id _legacy_last_token_col;
        column_id _legacy_generation_number_col;
        const query::partition_slice& _legacy_slice;
        query::partition_slice _slice;
        flat_mutation_reader _underlying;
        std::optional<clustering_key> _previous_clustering_key;

        build_progress_reader(
                schema_ptr legacy_schema,
                column_family& scylla_views_build_progress,
                const dht::partition_range& range,
                const query::partition_slice& slice,
                const io_priority_class& pc,
                tracing::trace_state_ptr trace_state,
                streamed_mutation::forwarding fwd,
                mutation_reader::forwarding fwd_mr)
                : flat_mutation_reader::impl(std::move(legacy_schema))
                , _scylla_next_token_col(scylla_views_build_progress.schema()->get_column_definition("next_token")->id)
                , _scylla_generation_number_col(scylla_views_build_progress.schema()->get_column_definition("generation_number")->id)
                , _legacy_last_token_col(_schema->get_column_definition("last_token")->id)
                , _legacy_generation_number_col(_schema->get_column_definition("generation_number")->id)
                , _legacy_slice(slice)
                , _slice(adjust_partition_slice())
                , _underlying(scylla_views_build_progress.make_reader(
                        scylla_views_build_progress.schema(),
                        range,
                        slice,
                        pc,
                        std::move(trace_state),
                        fwd,
                        fwd_mr))
                , _previous_clustering_key() {
        }

        const schema& underlying_schema() const {
            return *_underlying.schema();
        }

        query::partition_slice adjust_partition_slice() {
            auto slice = _legacy_slice;
            query::column_id_vector adjusted_columns;
            for (auto col_id : slice.regular_columns) {
                if (col_id == _legacy_last_token_col) {
                    adjusted_columns.push_back(_scylla_next_token_col);
                } else if (col_id == _legacy_generation_number_col) {
                    adjusted_columns.push_back(_scylla_generation_number_col);
                }
            }
            slice.regular_columns = std::move(adjusted_columns);
            return slice;
        }

        clustering_key adjust_ckey(clustering_key& underlying_ck) {
            if (!underlying_ck.is_full(underlying_schema())) {
                return std::move(underlying_ck);
            }
            // Drop the cpu_id from the clustering key
            auto end = underlying_ck.begin(underlying_schema());
            std::advance(end, underlying_schema().clustering_key_size() - 1);
            auto r = boost::make_iterator_range(underlying_ck.begin(underlying_schema()), std::move(end));
            return clustering_key_prefix::from_exploded(r);
        }

        virtual future<> fill_buffer(db::timeout_clock::time_point timeout) override {
            return _underlying.fill_buffer(timeout).then([this] {
                _end_of_stream = _underlying.is_end_of_stream();
                while (!_underlying.is_buffer_empty()) {
                    auto mf = _underlying.pop_mutation_fragment();
                    if (mf.is_clustering_row()) {
                        auto scylla_in_progress_row = std::move(mf).as_clustering_row();
                        auto legacy_in_progress_row = row();
                        // Drop the first_token from the regular columns
                        scylla_in_progress_row.cells().for_each_cell([&, this] (column_id id, atomic_cell_or_collection& c) {
                            if (id == _scylla_next_token_col) {
                                legacy_in_progress_row.append_cell(_legacy_last_token_col, std::move(c));
                            } else if (id == _scylla_generation_number_col) {
                                legacy_in_progress_row.append_cell(_legacy_generation_number_col, std::move(c));
                            }
                        });
                        auto ck = adjust_ckey(scylla_in_progress_row.key());
                        if (_previous_clustering_key && ck.equal(*_schema, *_previous_clustering_key)) {
                            continue;
                        }
                        _previous_clustering_key = ck;
                        mf = clustering_row(
                                std::move(ck),
                                std::move(scylla_in_progress_row.tomb()),
                                std::move(scylla_in_progress_row.marker()),
                                std::move(legacy_in_progress_row));
                    } else if (mf.is_range_tombstone()) {
                        auto scylla_in_progress_rt = std::move(mf).as_range_tombstone();
                        mf = range_tombstone(
                                adjust_ckey(scylla_in_progress_rt.start),
                                scylla_in_progress_rt.start_kind,
                                adjust_ckey(scylla_in_progress_rt.end),
                                scylla_in_progress_rt.end_kind,
                                scylla_in_progress_rt.tomb);
                    } else if (mf.is_end_of_partition()) {
                        _previous_clustering_key.reset();
                    }
                    push_mutation_fragment(std::move(mf));
                }
            });
        }

        virtual void next_partition() override {
            _end_of_stream = false;
            clear_buffer_to_next_partition();
            if (is_buffer_empty()) {
                _underlying.next_partition();
            }
        }

        virtual future<> fast_forward_to(const dht::partition_range& pr, db::timeout_clock::time_point timeout) override {
            clear_buffer();
            _end_of_stream = false;
            return _underlying.fast_forward_to(pr, timeout);
        }

        virtual future<> fast_forward_to(position_range range, db::timeout_clock::time_point timeout) override {
            forward_buffer_to(range.start());
            _end_of_stream = false;
            return _underlying.fast_forward_to(std::move(range), timeout);
        }
    };

public:
    build_progress_virtual_reader(database& db)
            : _db(db) {
    }

    flat_mutation_reader operator()(
            schema_ptr s,
            const dht::partition_range& range,
            const query::partition_slice& slice,
            const io_priority_class& pc,
            tracing::trace_state_ptr trace_state,
            streamed_mutation::forwarding fwd,
            mutation_reader::forwarding fwd_mr) {
        return flat_mutation_reader(std::make_unique<build_progress_reader>(
                std::move(s),
                _db.find_column_family(s->ks_name(), system_keyspace::v3::SCYLLA_VIEWS_BUILDS_IN_PROGRESS),
                range,
                slice,
                pc,
                std::move(trace_state),
                fwd,
                fwd_mr));
    }
};

}
<|endoftext|>


<commit_before>//--------------------------------------------------------------------*- C++ -*-
// CLING - the C++ LLVM-based InterpreterG :)
// version: $Id$
// author:  Axel Naumann <axel@cern.ch>
//------------------------------------------------------------------------------

#include "ExecutionContext.h"

#include "cling/Interpreter/StoredValueRef.h"

#include "llvm/Module.h"
#include "llvm/PassManager.h"
#include "llvm/Analysis/Verifier.h"
#include "llvm/Assembly/PrintModulePass.h"
#include "llvm/ExecutionEngine/JIT.h"
#include "llvm/ExecutionEngine/JITEventListener.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/DynamicLibrary.h"

using namespace cling;

namespace {
  class JITtedFunctionCollector : public llvm::JITEventListener {
  private:
    llvm::SmallVector<llvm::Function*, 24> m_functions;
    llvm::ExecutionEngine *m_engine;

  public:
    JITtedFunctionCollector(): m_functions(), m_engine(0) { }
    virtual ~JITtedFunctionCollector() { }

    virtual void NotifyFunctionEmitted(const llvm::Function& F, void *, size_t,
                              const JITEventListener::EmittedFunctionDetails&) {
      m_functions.push_back(const_cast<llvm::Function *>(&F));
    }
    virtual void NotifyFreeingMachineCode(void* /*OldPtr*/) {}

    void UnregisterFunctionMapping(llvm::ExecutionEngine&);
  };
}

void JITtedFunctionCollector::UnregisterFunctionMapping(
                                                  llvm::ExecutionEngine &engine)
{
  for (llvm::SmallVectorImpl<llvm::Function *>::reverse_iterator
         it = m_functions.rbegin(), et = m_functions.rend();
       it != et; ++it) {
    llvm::Function *ff = *it;
    engine.freeMachineCodeForFunction(ff);
    engine.updateGlobalMapping(ff, 0);
  }
  m_functions.clear();
}

std::set<std::string> ExecutionContext::m_unresolvedSymbols;
std::vector<ExecutionContext::LazyFunctionCreatorFunc_t>
  ExecutionContext::m_lazyFuncCreator;

bool ExecutionContext::m_LazyFuncCreatorDiagsSuppressed = true;

ExecutionContext::ExecutionContext():
  m_engine(0),
  m_RunningStaticInits(false),
  m_CxaAtExitRemapped(false)
{
}

void
ExecutionContext::InitializeBuilder(llvm::Module* m)
{
  //
  //  Create an execution engine to use.
  //
  // Note: Engine takes ownership of the module.
  assert(m && "Module cannot be null");

  llvm::EngineBuilder builder(m);
  builder.setOptLevel(llvm::CodeGenOpt::Less);
  std::string errMsg;
  builder.setErrorStr(&errMsg);
  builder.setEngineKind(llvm::EngineKind::JIT);
  builder.setAllocateGVsWithCode(false);
  m_engine = builder.create();
  assert(m_engine && "Cannot initialize builder without module!");

  //m_engine->addModule(m); // Note: The engine takes ownership of the module.

  // install lazy function
  m_engine->InstallLazyFunctionCreator(NotifyLazyFunctionCreators);
}

ExecutionContext::~ExecutionContext()
{
}

void unresolvedSymbol()
{
  // throw exception?
  llvm::errs() << "ExecutionContext: calling unresolved symbol (should never happen)!\n";
}

void* ExecutionContext::HandleMissingFunction(const std::string& mangled_name)
{
  // Not found in the map, add the symbol in the list of unresolved symbols
  if (m_unresolvedSymbols.insert(mangled_name).second) {
    llvm::errs() << "ExecutionContext: use of undefined symbol '"
                 << mangled_name << "'!\n";
  }

  // Avoid "ISO C++ forbids casting between pointer-to-function and
  // pointer-to-object":
  return (void*)reinterpret_cast<size_t>(unresolvedSymbol);
}

void*
ExecutionContext::NotifyLazyFunctionCreators(const std::string& mangled_name)
{
  for (std::vector<LazyFunctionCreatorFunc_t>::iterator it
         = m_lazyFuncCreator.begin(), et = m_lazyFuncCreator.end();
       it != et; ++it) {
    void* ret = (void*)((LazyFunctionCreatorFunc_t)*it)(mangled_name);
    if (ret)
      return ret;
  }

  if (!m_LazyFuncCreatorDiagsSuppressed)
    return 0;

  return HandleMissingFunction(mangled_name);
}

void
ExecutionContext::executeFunction(llvm::StringRef funcname,
                                  const clang::ASTContext& Ctx,
                                  clang::QualType retType,
                                  StoredValueRef* returnValue)
{
  // Call a function without arguments, or with an SRet argument, see SRet below

  if (!m_CxaAtExitRemapped) {
    // Rewire atexit:
    llvm::Function* atExit = m_engine->FindFunctionNamed("__cxa_atexit");
    llvm::Function* clingAtExit = m_engine->FindFunctionNamed("cling_cxa_atexit");
    if (atExit && clingAtExit) {
      void* clingAtExitAddr = m_engine->getPointerToFunction(clingAtExit);
      assert(clingAtExitAddr && "cannot find cling_cxa_atexit");
      m_engine->updateGlobalMapping(atExit, clingAtExitAddr);
      m_CxaAtExitRemapped = true;
    }
  }

  // We don't care whether something was unresolved before.
  m_unresolvedSymbols.clear();

  llvm::Function* f = m_engine->FindFunctionNamed(funcname.data());
  if (!f) {
    llvm::errs() << "ExecutionContext::executeFunction: could not find function named " << funcname << '\n';
    return;
  }
  JITtedFunctionCollector listener;
  // register the listener
  m_engine->RegisterJITEventListener(&listener);
  m_engine->getPointerToFunction(f);
  // check if there is any unresolved symbol in the list
  if (!m_unresolvedSymbols.empty()) {
    for (std::set<std::string>::const_iterator i = m_unresolvedSymbols.begin(),
           e = m_unresolvedSymbols.end(); i != e; ++i) {
      llvm::errs() << "ExecutionContext::executeFunction: symbol \'" << *i << "\' unresolved!\n";
      llvm::Function *ff = m_engine->FindFunctionNamed(i->c_str());
      assert(ff && "cannot find function to free");
      m_engine->updateGlobalMapping(ff, 0);
      m_engine->freeMachineCodeForFunction(ff);
    }
    m_unresolvedSymbols.clear();
    // cleanup functions
    listener.UnregisterFunctionMapping(*m_engine);
    m_engine->UnregisterJITEventListener(&listener);
    return;
  }
  // cleanup list and unregister our listener
  m_engine->UnregisterJITEventListener(&listener);

  std::vector<llvm::GenericValue> args;
  bool wantReturn = (returnValue);
  StoredValueRef aggregateRet;

  if (f->hasStructRetAttr()) {
    // Function expects to receive the storage for the returned aggregate as
    // first argument. Allocate returnValue:
    aggregateRet = StoredValueRef::allocate(Ctx, retType);
    if (returnValue) {
      *returnValue = aggregateRet;
    } else {
      returnValue = &aggregateRet;
    }
    args.push_back(returnValue->get().value);
    // will get set as arg0, must not assign.
    wantReturn = false;
  }

  if (wantReturn) {
    llvm::GenericValue gvRet = m_engine->runFunction(f, args);
    // rescue the ret value (which might be aggregate) from the stack
    *returnValue = StoredValueRef::bitwiseCopy(Ctx, Value(gvRet, retType));
  } else {
    m_engine->runFunction(f, args);
  }

  m_engine->freeMachineCodeForFunction(f);
}

void
ExecutionContext::runStaticInitializersOnce(llvm::Module* m) {
  assert(m && "Module must not be null");

  if (!m_engine)
    InitializeBuilder(m);

  assert(m_engine && "Code generation did not create an engine!");

  if (!m_RunningStaticInits) {
    m_RunningStaticInits = true;

    llvm::GlobalVariable* gctors
      = m->getGlobalVariable("llvm.global_ctors", true);
    if (gctors) {
      m_engine->runStaticConstructorsDestructors(false);
      gctors->eraseFromParent();
    }

    m_RunningStaticInits = false;
  }
}

void
ExecutionContext::runStaticDestructorsOnce(llvm::Module* m) {
  assert(m && "Module must not be null");
  assert(m_engine && "Code generation did not create an engine!");

  llvm::GlobalVariable* gdtors
    = m->getGlobalVariable("llvm.global_dtors", true);
  if (gdtors) {
    m_engine->runStaticConstructorsDestructors(true);
  }

}

int
ExecutionContext::verifyModule(llvm::Module* m)
{
  //
  //  Verify generated module.
  //
  bool mod_has_errs = llvm::verifyModule(*m, llvm::PrintMessageAction);
  if (mod_has_errs) {
    return 1;
  }
  return 0;
}

void
ExecutionContext::printModule(llvm::Module* m)
{
  //
  //  Print module LLVM code in human-readable form.
  //
  llvm::PassManager PM;
  PM.add(llvm::createPrintModulePass(&llvm::outs()));
  PM.run(*m);
}

void
ExecutionContext::installLazyFunctionCreator(LazyFunctionCreatorFunc_t fp)
{
  m_lazyFuncCreator.push_back(fp);
}

bool ExecutionContext::addSymbol(const char* symbolName,  void* symbolAddress) {

  void* actualAddress
    = llvm::sys::DynamicLibrary::SearchForAddressOfSymbol(symbolName);
  if (actualAddress)
    return false;

  llvm::sys::DynamicLibrary::AddSymbol(symbolName, symbolAddress);
  return true;
}

void* ExecutionContext::getAddressOfGlobal(llvm::Module* m,
                                           const char* symbolName,
                                           bool* fromJIT /*=0*/) const {
    // Return a symbol's address, and whether it was jitted.
    void* address
      = llvm::sys::DynamicLibrary::SearchForAddressOfSymbol(symbolName);
    if (address) {
      if (fromJIT) *fromJIT = false;
    } else {
      if (fromJIT) *fromJIT = true;
      llvm::GlobalVariable* gvar
        = m->getGlobalVariable(symbolName, true);
      if (!gvar)
        return 0;

      address = m_engine->getPointerToGlobal(gvar);
    }
    return address;
  }
<commit_msg>Flip the flag, because of the name change.<commit_after>//--------------------------------------------------------------------*- C++ -*-
// CLING - the C++ LLVM-based InterpreterG :)
// version: $Id$
// author:  Axel Naumann <axel@cern.ch>
//------------------------------------------------------------------------------

#include "ExecutionContext.h"

#include "cling/Interpreter/StoredValueRef.h"

#include "llvm/Module.h"
#include "llvm/PassManager.h"
#include "llvm/Analysis/Verifier.h"
#include "llvm/Assembly/PrintModulePass.h"
#include "llvm/ExecutionEngine/JIT.h"
#include "llvm/ExecutionEngine/JITEventListener.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/DynamicLibrary.h"

using namespace cling;

namespace {
  class JITtedFunctionCollector : public llvm::JITEventListener {
  private:
    llvm::SmallVector<llvm::Function*, 24> m_functions;
    llvm::ExecutionEngine *m_engine;

  public:
    JITtedFunctionCollector(): m_functions(), m_engine(0) { }
    virtual ~JITtedFunctionCollector() { }

    virtual void NotifyFunctionEmitted(const llvm::Function& F, void *, size_t,
                              const JITEventListener::EmittedFunctionDetails&) {
      m_functions.push_back(const_cast<llvm::Function *>(&F));
    }
    virtual void NotifyFreeingMachineCode(void* /*OldPtr*/) {}

    void UnregisterFunctionMapping(llvm::ExecutionEngine&);
  };
}

void JITtedFunctionCollector::UnregisterFunctionMapping(
                                                  llvm::ExecutionEngine &engine)
{
  for (llvm::SmallVectorImpl<llvm::Function *>::reverse_iterator
         it = m_functions.rbegin(), et = m_functions.rend();
       it != et; ++it) {
    llvm::Function *ff = *it;
    engine.freeMachineCodeForFunction(ff);
    engine.updateGlobalMapping(ff, 0);
  }
  m_functions.clear();
}

std::set<std::string> ExecutionContext::m_unresolvedSymbols;
std::vector<ExecutionContext::LazyFunctionCreatorFunc_t>
  ExecutionContext::m_lazyFuncCreator;

bool ExecutionContext::m_LazyFuncCreatorDiagsSuppressed = true;

ExecutionContext::ExecutionContext():
  m_engine(0),
  m_RunningStaticInits(false),
  m_CxaAtExitRemapped(false)
{
}

void
ExecutionContext::InitializeBuilder(llvm::Module* m)
{
  //
  //  Create an execution engine to use.
  //
  // Note: Engine takes ownership of the module.
  assert(m && "Module cannot be null");

  llvm::EngineBuilder builder(m);
  builder.setOptLevel(llvm::CodeGenOpt::Less);
  std::string errMsg;
  builder.setErrorStr(&errMsg);
  builder.setEngineKind(llvm::EngineKind::JIT);
  builder.setAllocateGVsWithCode(false);
  m_engine = builder.create();
  assert(m_engine && "Cannot initialize builder without module!");

  //m_engine->addModule(m); // Note: The engine takes ownership of the module.

  // install lazy function
  m_engine->InstallLazyFunctionCreator(NotifyLazyFunctionCreators);
}

ExecutionContext::~ExecutionContext()
{
}

void unresolvedSymbol()
{
  // throw exception?
  llvm::errs() << "ExecutionContext: calling unresolved symbol (should never happen)!\n";
}

void* ExecutionContext::HandleMissingFunction(const std::string& mangled_name)
{
  // Not found in the map, add the symbol in the list of unresolved symbols
  if (m_unresolvedSymbols.insert(mangled_name).second) {
    llvm::errs() << "ExecutionContext: use of undefined symbol '"
                 << mangled_name << "'!\n";
  }

  // Avoid "ISO C++ forbids casting between pointer-to-function and
  // pointer-to-object":
  return (void*)reinterpret_cast<size_t>(unresolvedSymbol);
}

void*
ExecutionContext::NotifyLazyFunctionCreators(const std::string& mangled_name)
{
  for (std::vector<LazyFunctionCreatorFunc_t>::iterator it
         = m_lazyFuncCreator.begin(), et = m_lazyFuncCreator.end();
       it != et; ++it) {
    void* ret = (void*)((LazyFunctionCreatorFunc_t)*it)(mangled_name);
    if (ret)
      return ret;
  }

  if (m_LazyFuncCreatorDiagsSuppressed)
    return 0;

  return HandleMissingFunction(mangled_name);
}

void
ExecutionContext::executeFunction(llvm::StringRef funcname,
                                  const clang::ASTContext& Ctx,
                                  clang::QualType retType,
                                  StoredValueRef* returnValue)
{
  // Call a function without arguments, or with an SRet argument, see SRet below

  if (!m_CxaAtExitRemapped) {
    // Rewire atexit:
    llvm::Function* atExit = m_engine->FindFunctionNamed("__cxa_atexit");
    llvm::Function* clingAtExit = m_engine->FindFunctionNamed("cling_cxa_atexit");
    if (atExit && clingAtExit) {
      void* clingAtExitAddr = m_engine->getPointerToFunction(clingAtExit);
      assert(clingAtExitAddr && "cannot find cling_cxa_atexit");
      m_engine->updateGlobalMapping(atExit, clingAtExitAddr);
      m_CxaAtExitRemapped = true;
    }
  }

  // We don't care whether something was unresolved before.
  m_unresolvedSymbols.clear();

  llvm::Function* f = m_engine->FindFunctionNamed(funcname.data());
  if (!f) {
    llvm::errs() << "ExecutionContext::executeFunction: could not find function named " << funcname << '\n';
    return;
  }
  JITtedFunctionCollector listener;
  // register the listener
  m_engine->RegisterJITEventListener(&listener);
  m_engine->getPointerToFunction(f);
  // check if there is any unresolved symbol in the list
  if (!m_unresolvedSymbols.empty()) {
    for (std::set<std::string>::const_iterator i = m_unresolvedSymbols.begin(),
           e = m_unresolvedSymbols.end(); i != e; ++i) {
      llvm::errs() << "ExecutionContext::executeFunction: symbol \'" << *i << "\' unresolved!\n";
      llvm::Function *ff = m_engine->FindFunctionNamed(i->c_str());
      assert(ff && "cannot find function to free");
      m_engine->updateGlobalMapping(ff, 0);
      m_engine->freeMachineCodeForFunction(ff);
    }
    m_unresolvedSymbols.clear();
    // cleanup functions
    listener.UnregisterFunctionMapping(*m_engine);
    m_engine->UnregisterJITEventListener(&listener);
    return;
  }
  // cleanup list and unregister our listener
  m_engine->UnregisterJITEventListener(&listener);

  std::vector<llvm::GenericValue> args;
  bool wantReturn = (returnValue);
  StoredValueRef aggregateRet;

  if (f->hasStructRetAttr()) {
    // Function expects to receive the storage for the returned aggregate as
    // first argument. Allocate returnValue:
    aggregateRet = StoredValueRef::allocate(Ctx, retType);
    if (returnValue) {
      *returnValue = aggregateRet;
    } else {
      returnValue = &aggregateRet;
    }
    args.push_back(returnValue->get().value);
    // will get set as arg0, must not assign.
    wantReturn = false;
  }

  if (wantReturn) {
    llvm::GenericValue gvRet = m_engine->runFunction(f, args);
    // rescue the ret value (which might be aggregate) from the stack
    *returnValue = StoredValueRef::bitwiseCopy(Ctx, Value(gvRet, retType));
  } else {
    m_engine->runFunction(f, args);
  }

  m_engine->freeMachineCodeForFunction(f);
}

void
ExecutionContext::runStaticInitializersOnce(llvm::Module* m) {
  assert(m && "Module must not be null");

  if (!m_engine)
    InitializeBuilder(m);

  assert(m_engine && "Code generation did not create an engine!");

  if (!m_RunningStaticInits) {
    m_RunningStaticInits = true;

    llvm::GlobalVariable* gctors
      = m->getGlobalVariable("llvm.global_ctors", true);
    if (gctors) {
      m_engine->runStaticConstructorsDestructors(false);
      gctors->eraseFromParent();
    }

    m_RunningStaticInits = false;
  }
}

void
ExecutionContext::runStaticDestructorsOnce(llvm::Module* m) {
  assert(m && "Module must not be null");
  assert(m_engine && "Code generation did not create an engine!");

  llvm::GlobalVariable* gdtors
    = m->getGlobalVariable("llvm.global_dtors", true);
  if (gdtors) {
    m_engine->runStaticConstructorsDestructors(true);
  }

}

int
ExecutionContext::verifyModule(llvm::Module* m)
{
  //
  //  Verify generated module.
  //
  bool mod_has_errs = llvm::verifyModule(*m, llvm::PrintMessageAction);
  if (mod_has_errs) {
    return 1;
  }
  return 0;
}

void
ExecutionContext::printModule(llvm::Module* m)
{
  //
  //  Print module LLVM code in human-readable form.
  //
  llvm::PassManager PM;
  PM.add(llvm::createPrintModulePass(&llvm::outs()));
  PM.run(*m);
}

void
ExecutionContext::installLazyFunctionCreator(LazyFunctionCreatorFunc_t fp)
{
  m_lazyFuncCreator.push_back(fp);
}

bool ExecutionContext::addSymbol(const char* symbolName,  void* symbolAddress) {

  void* actualAddress
    = llvm::sys::DynamicLibrary::SearchForAddressOfSymbol(symbolName);
  if (actualAddress)
    return false;

  llvm::sys::DynamicLibrary::AddSymbol(symbolName, symbolAddress);
  return true;
}

void* ExecutionContext::getAddressOfGlobal(llvm::Module* m,
                                           const char* symbolName,
                                           bool* fromJIT /*=0*/) const {
    // Return a symbol's address, and whether it was jitted.
    void* address
      = llvm::sys::DynamicLibrary::SearchForAddressOfSymbol(symbolName);
    if (address) {
      if (fromJIT) *fromJIT = false;
    } else {
      if (fromJIT) *fromJIT = true;
      llvm::GlobalVariable* gvar
        = m->getGlobalVariable(symbolName, true);
      if (!gvar)
        return 0;

      address = m_engine->getPointerToGlobal(gvar);
    }
    return address;
  }
<|endoftext|>


<commit_before>//===- FileOutputBuffer.cpp - File Output Buffer ----------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Utility for creating a in-memory buffer that will be written to a file.
//
//===----------------------------------------------------------------------===//

#include "llvm/Support/FileOutputBuffer.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/Errc.h"
#include "llvm/Support/Memory.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Signals.h"
#include <system_error>

#if !defined(_MSC_VER) && !defined(__MINGW32__)
#include <unistd.h>
#else
#include <io.h>
#endif

using namespace llvm;
using namespace llvm::sys;

// A FileOutputBuffer which creates a temporary file in the same directory
// as the final output file. The final output file is atomically replaced
// with the temporary file on commit().
class OnDiskBuffer : public FileOutputBuffer {
public:
  OnDiskBuffer(StringRef Path, StringRef TempPath,
               std::unique_ptr<fs::mapped_file_region> Buf)
      : FileOutputBuffer(Path), Buffer(std::move(Buf)), TempPath(TempPath) {}

  static Expected<std::unique_ptr<OnDiskBuffer>>
  create(StringRef Path, size_t Size, unsigned Mode);

  uint8_t *getBufferStart() const override { return (uint8_t *)Buffer->data(); }

  uint8_t *getBufferEnd() const override {
    return (uint8_t *)Buffer->data() + Buffer->size();
  }

  size_t getBufferSize() const override { return Buffer->size(); }

  Error commit() override {
    // Unmap buffer, letting OS flush dirty pages to file on disk.
    Buffer.reset();

    // Atomically replace the existing file with the new one.
    auto EC = fs::rename(TempPath, FinalPath);
    sys::DontRemoveFileOnSignal(TempPath);
    return errorCodeToError(EC);
  }

  ~OnDiskBuffer() override {
    // Close the mapping before deleting the temp file, so that the removal
    // succeeds.
    Buffer.reset();
    fs::remove(TempPath);
  }

private:
  std::unique_ptr<fs::mapped_file_region> Buffer;
  std::string TempPath;
};

// A FileOutputBuffer which keeps data in memory and writes to the final
// output file on commit(). This is used only when we cannot use OnDiskBuffer.
class InMemoryBuffer : public FileOutputBuffer {
public:
  InMemoryBuffer(StringRef Path, MemoryBlock Buf, unsigned Mode)
      : FileOutputBuffer(Path), Buffer(Buf), Mode(Mode) {}

  static Expected<std::unique_ptr<InMemoryBuffer>>
  create(StringRef Path, size_t Size, unsigned Mode) {
    std::error_code EC;
    MemoryBlock MB = Memory::allocateMappedMemory(
        Size, nullptr, sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC);
    if (EC)
      return errorCodeToError(EC);
    return llvm::make_unique<InMemoryBuffer>(Path, MB, Mode);
  }

  uint8_t *getBufferStart() const override { return (uint8_t *)Buffer.base(); }

  uint8_t *getBufferEnd() const override {
    return (uint8_t *)Buffer.base() + Buffer.size();
  }

  size_t getBufferSize() const override { return Buffer.size(); }

  Error commit() override {
    int FD;
    std::error_code EC;
    if (auto EC = openFileForWrite(FinalPath, FD, fs::F_None, Mode))
      return errorCodeToError(EC);
    raw_fd_ostream OS(FD, /*shouldClose=*/true, /*unbuffered=*/true);
    OS << StringRef((const char *)Buffer.base(), Buffer.size());
    return Error::success();
  }

private:
  OwningMemoryBlock Buffer;
  unsigned Mode;
};

Expected<std::unique_ptr<OnDiskBuffer>>
OnDiskBuffer::create(StringRef Path, size_t Size, unsigned Mode) {
  // Create new file in same directory but with random name.
  SmallString<128> TempPath;
  int FD;
  if (auto EC = fs::createUniqueFile(Path + ".tmp%%%%%%%", FD, TempPath, Mode))
    return errorCodeToError(EC);

  sys::RemoveFileOnSignal(TempPath);

#ifndef LLVM_ON_WIN32
  // On Windows, CreateFileMapping (the mmap function on Windows)
  // automatically extends the underlying file. We don't need to
  // extend the file beforehand. _chsize (ftruncate on Windows) is
  // pretty slow just like it writes specified amount of bytes,
  // so we should avoid calling that function.
  if (auto EC = fs::resize_file(FD, Size))
    return errorCodeToError(EC);
#endif

  // Mmap it.
  std::error_code EC;
  auto MappedFile = llvm::make_unique<fs::mapped_file_region>(
      FD, fs::mapped_file_region::readwrite, Size, 0, EC);
  close(FD);
  if (EC)
    return errorCodeToError(EC);
  return llvm::make_unique<OnDiskBuffer>(Path, TempPath, std::move(MappedFile));
}

// Create an instance of FileOutputBuffer.
Expected<std::unique_ptr<FileOutputBuffer>>
FileOutputBuffer::create(StringRef Path, size_t Size, unsigned Flags) {
  unsigned Mode = fs::all_read | fs::all_write;
  if (Flags & F_executable)
    Mode |= fs::all_exe;

  fs::file_status Stat;
  fs::status(Path, Stat);

  // Usually, we want to create OnDiskBuffer to create a temporary file in
  // the same directory as the destination file and atomically replaces it
  // by rename(2).
  //
  // However, if the destination file is a special file, we don't want to
  // use rename (e.g. we don't want to replace /dev/null with a regular
  // file.) If that's the case, we create an in-memory buffer, open the
  // destination file and write to it on commit().
  switch (Stat.type()) {
  case fs::file_type::directory_file:
    return errorCodeToError(errc::is_a_directory);
  case fs::file_type::regular_file:
  case fs::file_type::file_not_found:
  case fs::file_type::status_error:
    return OnDiskBuffer::create(Path, Size, Mode);
  default:
    return InMemoryBuffer::create(Path, Size, Mode);
  }
}
<commit_msg>[FileOutputBuffer] Move factory methods out of their classes.<commit_after>//===- FileOutputBuffer.cpp - File Output Buffer ----------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Utility for creating a in-memory buffer that will be written to a file.
//
//===----------------------------------------------------------------------===//

#include "llvm/Support/FileOutputBuffer.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/Support/Errc.h"
#include "llvm/Support/Memory.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Signals.h"
#include <system_error>

#if !defined(_MSC_VER) && !defined(__MINGW32__)
#include <unistd.h>
#else
#include <io.h>
#endif

using namespace llvm;
using namespace llvm::sys;

// A FileOutputBuffer which creates a temporary file in the same directory
// as the final output file. The final output file is atomically replaced
// with the temporary file on commit().
class OnDiskBuffer : public FileOutputBuffer {
public:
  OnDiskBuffer(StringRef Path, StringRef TempPath,
               std::unique_ptr<fs::mapped_file_region> Buf)
      : FileOutputBuffer(Path), Buffer(std::move(Buf)), TempPath(TempPath) {}

  uint8_t *getBufferStart() const override { return (uint8_t *)Buffer->data(); }

  uint8_t *getBufferEnd() const override {
    return (uint8_t *)Buffer->data() + Buffer->size();
  }

  size_t getBufferSize() const override { return Buffer->size(); }

  Error commit() override {
    // Unmap buffer, letting OS flush dirty pages to file on disk.
    Buffer.reset();

    // Atomically replace the existing file with the new one.
    auto EC = fs::rename(TempPath, FinalPath);
    sys::DontRemoveFileOnSignal(TempPath);
    return errorCodeToError(EC);
  }

  ~OnDiskBuffer() override {
    // Close the mapping before deleting the temp file, so that the removal
    // succeeds.
    Buffer.reset();
    fs::remove(TempPath);
  }

private:
  std::unique_ptr<fs::mapped_file_region> Buffer;
  std::string TempPath;
};

// A FileOutputBuffer which keeps data in memory and writes to the final
// output file on commit(). This is used only when we cannot use OnDiskBuffer.
class InMemoryBuffer : public FileOutputBuffer {
public:
  InMemoryBuffer(StringRef Path, MemoryBlock Buf, unsigned Mode)
      : FileOutputBuffer(Path), Buffer(Buf), Mode(Mode) {}

  uint8_t *getBufferStart() const override { return (uint8_t *)Buffer.base(); }

  uint8_t *getBufferEnd() const override {
    return (uint8_t *)Buffer.base() + Buffer.size();
  }

  size_t getBufferSize() const override { return Buffer.size(); }

  Error commit() override {
    int FD;
    std::error_code EC;
    if (auto EC = openFileForWrite(FinalPath, FD, fs::F_None, Mode))
      return errorCodeToError(EC);
    raw_fd_ostream OS(FD, /*shouldClose=*/true, /*unbuffered=*/true);
    OS << StringRef((const char *)Buffer.base(), Buffer.size());
    return Error::success();
  }

private:
  OwningMemoryBlock Buffer;
  unsigned Mode;
};

static Expected<std::unique_ptr<InMemoryBuffer>>
createInMemoryBuffer(StringRef Path, size_t Size, unsigned Mode) {
  std::error_code EC;
  MemoryBlock MB = Memory::allocateMappedMemory(
      Size, nullptr, sys::Memory::MF_READ | sys::Memory::MF_WRITE, EC);
  if (EC)
    return errorCodeToError(EC);
  return llvm::make_unique<InMemoryBuffer>(Path, MB, Mode);
}

static Expected<std::unique_ptr<OnDiskBuffer>>
createOnDiskBuffer(StringRef Path, size_t Size, unsigned Mode) {
  // Create new file in same directory but with random name.
  SmallString<128> TempPath;
  int FD;
  if (auto EC = fs::createUniqueFile(Path + ".tmp%%%%%%%", FD, TempPath, Mode))
    return errorCodeToError(EC);

  sys::RemoveFileOnSignal(TempPath);

#ifndef LLVM_ON_WIN32
  // On Windows, CreateFileMapping (the mmap function on Windows)
  // automatically extends the underlying file. We don't need to
  // extend the file beforehand. _chsize (ftruncate on Windows) is
  // pretty slow just like it writes specified amount of bytes,
  // so we should avoid calling that function.
  if (auto EC = fs::resize_file(FD, Size))
    return errorCodeToError(EC);
#endif

  // Mmap it.
  std::error_code EC;
  auto MappedFile = llvm::make_unique<fs::mapped_file_region>(
      FD, fs::mapped_file_region::readwrite, Size, 0, EC);
  close(FD);
  if (EC)
    return errorCodeToError(EC);
  return llvm::make_unique<OnDiskBuffer>(Path, TempPath, std::move(MappedFile));
}

// Create an instance of FileOutputBuffer.
Expected<std::unique_ptr<FileOutputBuffer>>
FileOutputBuffer::create(StringRef Path, size_t Size, unsigned Flags) {
  unsigned Mode = fs::all_read | fs::all_write;
  if (Flags & F_executable)
    Mode |= fs::all_exe;

  fs::file_status Stat;
  fs::status(Path, Stat);

  // Usually, we want to create OnDiskBuffer to create a temporary file in
  // the same directory as the destination file and atomically replaces it
  // by rename(2).
  //
  // However, if the destination file is a special file, we don't want to
  // use rename (e.g. we don't want to replace /dev/null with a regular
  // file.) If that's the case, we create an in-memory buffer, open the
  // destination file and write to it on commit().
  switch (Stat.type()) {
  case fs::file_type::directory_file:
    return errorCodeToError(errc::is_a_directory);
  case fs::file_type::regular_file:
  case fs::file_type::file_not_found:
  case fs::file_type::status_error:
    return createOnDiskBuffer(Path, Size, Mode);
  default:
    return createInMemoryBuffer(Path, Size, Mode);
  }
}
<|endoftext|>


<commit_before>//
//  riscv-test-emulate.cc
//

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cinttypes>
#include <cstdarg>
#include <cerrno>
#include <cassert>
#include <cmath>
#include <algorithm>
#include <limits>
#include <memory>
#include <string>
#include <vector>
#include <deque>
#include <map>
#include <set>

#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/stat.h>

#include "riscv-types.h"
#include "riscv-endian.h"
#include "riscv-format.h"
#include "riscv-meta.h"
#include "riscv-util.h"
#include "riscv-cmdline.h"
#include "riscv-codec.h"
#include "riscv-elf.h"
#include "riscv-elf-file.h"
#include "riscv-elf-format.h"
#include "riscv-strings.h"
#include "riscv-disasm.h"
#include "riscv-processor.h"
#include "riscv-abi.h"
#include "riscv-proxy.h"

inline float f32_sqrt(float a) { return std::sqrt(a); }
inline double f64_sqrt(double a) { return std::sqrt(a); }
inline float f32_classify(float a) { return 0; } /* unimplemented */
inline double f64_classify(double a) { return 0; } /* unimplemented */

namespace riscv {
	#include "riscv-interp.h"
}

using namespace riscv;

struct riscv_proc_proxy_rv64 : riscv_processor_rv64
{
	uintptr_t heap_begin;
	uintptr_t heap_end;
	std::vector<std::pair<void*,size_t>> mapped_segments;

	riscv_proc_proxy_rv64() : riscv_processor_rv64(), heap_begin(0), heap_end(0) {}
};

struct riscv_emulator
{
	static const size_t stack_top =  0x78000000; // 1920 MiB
	static const size_t stack_size = 0x01000000; //   16 MiB

	elf_file elf;
	std::string filename;

	struct riscv_inst_cache_ent
	{
		uint64_t inst;
		riscv_decode dec;
	};

	static const size_t inst_cache_size = 8191;
	riscv_inst_cache_ent inst_cache[inst_cache_size];

	bool memory_debug = false;
	bool emulator_debug = false;
	bool log_registers = false;
	bool log_instructions = false;
	bool help_or_error = false;

	/*
		This simple proof of concept machine emulator uses a
		machine generated interpreter in src/asm/riscv-interp.h
		created by parse-meta using C-psuedo code in meta/instructions
	*/

	inline static const int elf_p_flags_mmap(int v)
	{
		int prot = 0;
		if (v & PF_X) prot |= PROT_EXEC;
		if (v & PF_W) prot |= PROT_WRITE;
		if (v & PF_R) prot |= PROT_READ;
		return prot;
	}

	template <typename P>
	void print_int_regeisters(P &proc)
	{
		for (size_t i = 0; i < 32; i++) {
			char fmt[32];
			snprintf(fmt, sizeof(fmt), "%%-4s: 0x%%0%u%sx%%s",
				(P::xlen >> 2), P::xlen == 64 ? "ll" : "");
			printf(fmt, riscv_ireg_name_sym[i], proc.ireg[i].r.xu.val,
				(i + 1) % 4 == 0 ? "\n" : " ");
		}
	}

	template <typename P>
	void print_f32_regeisters(P &proc)
	{
		for (size_t i = 0; i < 32; i++) {
			printf("%-4s: s %16.5f%s", riscv_freg_name_sym[i],
				proc.freg[i].r.s.val, (i + 1) % 4 == 0 ? "\n" : " ");
		}
	}

	template <typename P>
	void print_f64_regeisters(P &proc)
	{
		for (size_t i = 0; i < 32; i++) {
			printf("%-4s: d %16.5f%s", riscv_freg_name_sym[i],
				proc.freg[i].r.d.val, (i + 1) % 4 == 0 ? "\n" : " ");
		}
	}

	std::string format_inst(uintptr_t pc)
	{
		char buf[20];
		uintptr_t inst_length;
		uint64_t inst = riscv_inst_fetch(pc, &inst_length);
		switch (inst_length) {
			case 2:  snprintf(buf, sizeof(buf), "0x%04tx", inst); break;
			case 4:  snprintf(buf, sizeof(buf), "0x%08tx", inst); break;
			case 6:  snprintf(buf, sizeof(buf), "0x%012tx", inst); break;
			case 8:  snprintf(buf, sizeof(buf), "0x%016tx", inst); break;
			default: snprintf(buf, sizeof(buf), "(invalid)"); break;
		}
		return buf;
	}

	template <typename T, typename P>
	void print_disassembly(T &dec, P &proc)
	{
		std::string args = riscv_disasm_inst_simple(dec);
		printf("core %3zu: 0x%016tx (%s) %-30s\n", proc.hart_id, proc.pc, format_inst(proc.pc).c_str(), args.c_str());
	}

	// Simple RV64 Linux syscall emulation (write, exit)
	template <typename P>
	void emulate_ecall(riscv_decode &dec, P &proc, uintptr_t inst_length)
	{
		switch (proc.ireg[riscv_ireg_a7]) {
			case riscv_syscall_close:  riscv_sys_close(proc); break;
			case riscv_syscall_write:  riscv_sys_write(proc); break;
			case riscv_syscall_fstat:  riscv_sys_fstat(proc); break;
			case riscv_syscall_exit:   riscv_sys_exit(proc);  break;
			case riscv_syscall_brk:    riscv_sys_brk(proc);   break;
			default: panic("unknown syscall: %d", proc.ireg[riscv_ireg_a7]);
		}
		proc.pc += inst_length;
	}

	// Simple RV64 emulator main loop
	template <typename P>
	void rv64_run(P &proc)
	{
		riscv_decode dec;
		size_t inst_length;
		uint64_t inst;
		while (true) {
			inst = riscv_inst_fetch(proc.pc, &inst_length);
			uint64_t inst_cache_key = inst % inst_cache_size;
			if (inst_cache[inst_cache_key].inst == inst) {
				dec = inst_cache[inst_cache_key].dec;
			} else {
				riscv_decode_inst_rv64(dec, inst);
				inst_cache[inst_cache_key].inst = inst;
				inst_cache[inst_cache_key].dec = dec;
			}
			if (log_registers) print_int_regeisters(proc);
			if (log_instructions) print_disassembly(dec, proc);
			if (riscv::rv64_exec(dec, proc, inst_length)) continue;
			if (dec.op == riscv_op_ecall) emulate_ecall(dec, proc, inst_length);
			else {
				panic("illegal instruciton: pc=0x%" PRIx64 " inst=0x%" PRIx64,
					proc.pc, inst);
			}
		}
	}

	// Simple code to map a single stack segment
	template <typename P>
	void map_stack(P &proc, uintptr_t stack_top, uintptr_t stack_size)
	{
		void *addr = mmap((void*)(stack_top - stack_size), stack_size,
			PROT_READ | PROT_WRITE, MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
		if (addr == MAP_FAILED) {
			panic("map_stack: error: mmap: %s", strerror(errno));
		}

		// keep track of the mapped segment and set the stack_top
		proc.mapped_segments.push_back(std::pair<void*,size_t>((void*)(stack_top - stack_size), stack_size));
		proc.ireg[riscv_ireg_sp] = stack_top - 0x8;

		if (emulator_debug) {
			debug("sp : mmap: 0x%016" PRIxPTR " - 0x%016" PRIxPTR " +R+W",
				(stack_top - stack_size), stack_top);
		}
	}

	// Simple code currently maps all segments copy-on-write RWX
	template <typename P>
	void map_load_segment(P &proc, const char* filename, Elf64_Phdr &phdr)
	{
		int fd = open(filename, O_RDONLY);
		if (fd < 0) {
			panic("map_executable: error: open: %s: %s", filename, strerror(errno));
		}
		void *addr = mmap((void*)phdr.p_vaddr, phdr.p_memsz,
			elf_p_flags_mmap(phdr.p_flags), MAP_FIXED | MAP_PRIVATE, fd, phdr.p_offset);
		close(fd);
		if (addr == MAP_FAILED) {
			panic("map_executable: error: mmap: %s: %s", filename, strerror(errno));
		}

		// keep track of the mapped segment and set the heap_end
		proc.mapped_segments.push_back(std::pair<void*,size_t>((void*)phdr.p_vaddr, phdr.p_memsz));
		uintptr_t seg_end = uintptr_t(phdr.p_vaddr + phdr.p_memsz);
		if (proc.heap_begin < seg_end) proc.heap_begin = proc.heap_end = seg_end;

		if (emulator_debug) {
			debug("elf: mmap: 0x%016" PRIxPTR " - 0x%016" PRIxPTR " %s",
				uintptr_t(phdr.p_vaddr), seg_end, elf_p_flags_name(phdr.p_flags).c_str());
		}
	}

	void parse_commandline(int argc, const char *argv[])
	{
		cmdline_option options[] =
		{
			{ "-m", "--memory-debug", cmdline_arg_type_none,
				"Memory debug",
				[&](std::string s) { return (memory_debug = true); } },
			{ "-d", "--emulator-debug", cmdline_arg_type_none,
				"Emulator debug",
				[&](std::string s) { return (emulator_debug = true); } },
			{ "-r", "--log-registers", cmdline_arg_type_none,
				"Log Registers",
				[&](std::string s) { return (log_registers = true); } },
			{ "-l", "--log-instructions", cmdline_arg_type_none,
				"Log Instructions",
				[&](std::string s) { return (log_instructions = true); } },
			{ "-h", "--help", cmdline_arg_type_none,
				"Show help",
				[&](std::string s) { return (help_or_error = true); } },
			{ nullptr, nullptr, cmdline_arg_type_none,   nullptr, nullptr }
		};

		auto result = cmdline_option::process_options(options, argc, argv);
		if (!result.second) {
			help_or_error = true;
		} else if (result.first.size() != 1) {
			printf("%s: wrong number of arguments\n", argv[0]);
			help_or_error = true;
		}

		if (help_or_error)
		{
			printf("usage: %s [<options>] <elf_file>\n", argv[0]);
			cmdline_option::print_options(options);
			exit(9);
		}

		filename = result.first[0];
	}

	// print approximate location of host text, heap and stack
	void memory_info(int argc, const char *argv[])
	{
		static const char *textptr = nullptr;
		void *heapptr = malloc(8);
		debug("text : ~0x%016" PRIxPTR, (uintptr_t)&textptr);
		debug("heap : ~0x%016" PRIxPTR, (uintptr_t)heapptr);
		debug("stack: ~0x%016" PRIxPTR, (uintptr_t)argv);
		free(heapptr);
	}

	void exec(int argc, const char *argv[])
	{
		// print process information
		if (memory_debug) {
			memory_info(argc, argv);
		}

		// load ELF (headers only)
		elf.load(filename, true);

		// Processor
		riscv_proc_proxy_rv64 proc;
		proc.flags = emulator_debug ? riscv_processor_flag_emulator_debug : 0;

		// Find the PT_LOAD segments and mmap then into memory
		for (size_t i = 0; i < elf.phdrs.size(); i++) {
			Elf64_Phdr &phdr = elf.phdrs[i];
			if (phdr.p_flags & PT_LOAD) {
				map_load_segment(proc, filename.c_str(), phdr);
			}
		}

		// Map a stack and set the stack pointer
		map_stack(proc, stack_top, stack_size);

		// Set the program counter to the entry address
		proc.pc = elf.ehdr.e_entry;

		// Start the emulator
		rv64_run(proc);

		// Unmap segments
		for (auto &seg: proc.mapped_segments) {
			munmap(seg.first, seg.second);
		}
	}
};

int main(int argc, const char *argv[])
{
	riscv_emulator emulator;
	emulator.parse_commandline(argc, argv);
	emulator.exec(argc, argv);
	return 0;
}
<commit_msg>Log FP registers in test-emulate when register logging is enabled<commit_after>//
//  riscv-test-emulate.cc
//

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cinttypes>
#include <cstdarg>
#include <cerrno>
#include <cassert>
#include <cmath>
#include <algorithm>
#include <limits>
#include <memory>
#include <string>
#include <vector>
#include <deque>
#include <map>
#include <set>

#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/stat.h>

#include "riscv-types.h"
#include "riscv-endian.h"
#include "riscv-format.h"
#include "riscv-meta.h"
#include "riscv-util.h"
#include "riscv-cmdline.h"
#include "riscv-codec.h"
#include "riscv-elf.h"
#include "riscv-elf-file.h"
#include "riscv-elf-format.h"
#include "riscv-strings.h"
#include "riscv-disasm.h"
#include "riscv-processor.h"
#include "riscv-abi.h"
#include "riscv-proxy.h"

inline float f32_sqrt(float a) { return std::sqrt(a); }
inline double f64_sqrt(double a) { return std::sqrt(a); }
inline float f32_classify(float a) { return 0; } /* unimplemented */
inline double f64_classify(double a) { return 0; } /* unimplemented */

namespace riscv {
	#include "riscv-interp.h"
}

using namespace riscv;

struct riscv_proc_proxy_rv64 : riscv_processor_rv64
{
	uintptr_t heap_begin;
	uintptr_t heap_end;
	std::vector<std::pair<void*,size_t>> mapped_segments;

	riscv_proc_proxy_rv64() : riscv_processor_rv64(), heap_begin(0), heap_end(0) {}
};

struct riscv_emulator
{
	static const size_t stack_top =  0x78000000; // 1920 MiB
	static const size_t stack_size = 0x01000000; //   16 MiB

	elf_file elf;
	std::string filename;

	struct riscv_inst_cache_ent
	{
		uint64_t inst;
		riscv_decode dec;
	};

	static const size_t inst_cache_size = 8191;
	riscv_inst_cache_ent inst_cache[inst_cache_size];

	bool memory_debug = false;
	bool emulator_debug = false;
	bool log_registers = false;
	bool log_instructions = false;
	bool help_or_error = false;

	/*
		This simple proof of concept machine emulator uses a
		machine generated interpreter in src/asm/riscv-interp.h
		created by parse-meta using C-psuedo code in meta/instructions
	*/

	inline static const int elf_p_flags_mmap(int v)
	{
		int prot = 0;
		if (v & PF_X) prot |= PROT_EXEC;
		if (v & PF_W) prot |= PROT_WRITE;
		if (v & PF_R) prot |= PROT_READ;
		return prot;
	}

	template <typename P>
	void print_int_regeisters(P &proc)
	{
		for (size_t i = 0; i < 32; i++) {
			char fmt[32];
			snprintf(fmt, sizeof(fmt), "%%-4s: 0x%%0%u%sx%%s",
				(P::xlen >> 2), P::xlen == 64 ? "ll" : "");
			printf(fmt, riscv_ireg_name_sym[i], proc.ireg[i].r.xu.val,
				(i + 1) % 4 == 0 ? "\n" : " ");
		}
	}

	template <typename P>
	void print_f32_regeisters(P &proc)
	{
		for (size_t i = 0; i < 32; i++) {
			printf("%-4s: s %16.5f%s", riscv_freg_name_sym[i],
				proc.freg[i].r.s.val, (i + 1) % 4 == 0 ? "\n" : " ");
		}
	}

	template <typename P>
	void print_f64_regeisters(P &proc)
	{
		for (size_t i = 0; i < 32; i++) {
			printf("%-4s: d %16.5f%s", riscv_freg_name_sym[i],
				proc.freg[i].r.d.val, (i + 1) % 4 == 0 ? "\n" : " ");
		}
	}

	std::string format_inst(uintptr_t pc)
	{
		char buf[20];
		uintptr_t inst_length;
		uint64_t inst = riscv_inst_fetch(pc, &inst_length);
		switch (inst_length) {
			case 2:  snprintf(buf, sizeof(buf), "0x%04tx", inst); break;
			case 4:  snprintf(buf, sizeof(buf), "0x%08tx", inst); break;
			case 6:  snprintf(buf, sizeof(buf), "0x%012tx", inst); break;
			case 8:  snprintf(buf, sizeof(buf), "0x%016tx", inst); break;
			default: snprintf(buf, sizeof(buf), "(invalid)"); break;
		}
		return buf;
	}

	template <typename T, typename P>
	void print_disassembly(T &dec, P &proc)
	{
		std::string args = riscv_disasm_inst_simple(dec);
		printf("core %3zu: 0x%016tx (%s) %-30s\n", proc.hart_id, proc.pc, format_inst(proc.pc).c_str(), args.c_str());
	}

	// Simple RV64 Linux syscall emulation (write, exit)
	template <typename P>
	void emulate_ecall(riscv_decode &dec, P &proc, uintptr_t inst_length)
	{
		switch (proc.ireg[riscv_ireg_a7]) {
			case riscv_syscall_close:  riscv_sys_close(proc); break;
			case riscv_syscall_write:  riscv_sys_write(proc); break;
			case riscv_syscall_fstat:  riscv_sys_fstat(proc); break;
			case riscv_syscall_exit:   riscv_sys_exit(proc);  break;
			case riscv_syscall_brk:    riscv_sys_brk(proc);   break;
			default: panic("unknown syscall: %d", proc.ireg[riscv_ireg_a7]);
		}
		proc.pc += inst_length;
	}

	// Simple RV64 emulator main loop
	template <typename P>
	void rv64_run(P &proc)
	{
		riscv_decode dec;
		size_t inst_length;
		uint64_t inst;
		while (true) {
			inst = riscv_inst_fetch(proc.pc, &inst_length);
			uint64_t inst_cache_key = inst % inst_cache_size;
			if (inst_cache[inst_cache_key].inst == inst) {
				dec = inst_cache[inst_cache_key].dec;
			} else {
				riscv_decode_inst_rv64(dec, inst);
				inst_cache[inst_cache_key].inst = inst;
				inst_cache[inst_cache_key].dec = dec;
			}
			if (log_registers) {
				print_int_regeisters(proc);
				print_f32_regeisters(proc);
				print_f64_regeisters(proc);
			}
			if (log_instructions) print_disassembly(dec, proc);
			if (riscv::rv64_exec(dec, proc, inst_length)) continue;
			if (dec.op == riscv_op_ecall) emulate_ecall(dec, proc, inst_length);
			else {
				panic("illegal instruciton: pc=0x%" PRIx64 " inst=0x%" PRIx64,
					proc.pc, inst);
			}
		}
	}

	// Simple code to map a single stack segment
	template <typename P>
	void map_stack(P &proc, uintptr_t stack_top, uintptr_t stack_size)
	{
		void *addr = mmap((void*)(stack_top - stack_size), stack_size,
			PROT_READ | PROT_WRITE, MAP_FIXED | MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
		if (addr == MAP_FAILED) {
			panic("map_stack: error: mmap: %s", strerror(errno));
		}

		// keep track of the mapped segment and set the stack_top
		proc.mapped_segments.push_back(std::pair<void*,size_t>((void*)(stack_top - stack_size), stack_size));
		proc.ireg[riscv_ireg_sp] = stack_top - 0x8;

		if (emulator_debug) {
			debug("sp : mmap: 0x%016" PRIxPTR " - 0x%016" PRIxPTR " +R+W",
				(stack_top - stack_size), stack_top);
		}
	}

	// Simple code currently maps all segments copy-on-write RWX
	template <typename P>
	void map_load_segment(P &proc, const char* filename, Elf64_Phdr &phdr)
	{
		int fd = open(filename, O_RDONLY);
		if (fd < 0) {
			panic("map_executable: error: open: %s: %s", filename, strerror(errno));
		}
		void *addr = mmap((void*)phdr.p_vaddr, phdr.p_memsz,
			elf_p_flags_mmap(phdr.p_flags), MAP_FIXED | MAP_PRIVATE, fd, phdr.p_offset);
		close(fd);
		if (addr == MAP_FAILED) {
			panic("map_executable: error: mmap: %s: %s", filename, strerror(errno));
		}

		// keep track of the mapped segment and set the heap_end
		proc.mapped_segments.push_back(std::pair<void*,size_t>((void*)phdr.p_vaddr, phdr.p_memsz));
		uintptr_t seg_end = uintptr_t(phdr.p_vaddr + phdr.p_memsz);
		if (proc.heap_begin < seg_end) proc.heap_begin = proc.heap_end = seg_end;

		if (emulator_debug) {
			debug("elf: mmap: 0x%016" PRIxPTR " - 0x%016" PRIxPTR " %s",
				uintptr_t(phdr.p_vaddr), seg_end, elf_p_flags_name(phdr.p_flags).c_str());
		}
	}

	void parse_commandline(int argc, const char *argv[])
	{
		cmdline_option options[] =
		{
			{ "-m", "--memory-debug", cmdline_arg_type_none,
				"Memory debug",
				[&](std::string s) { return (memory_debug = true); } },
			{ "-d", "--emulator-debug", cmdline_arg_type_none,
				"Emulator debug",
				[&](std::string s) { return (emulator_debug = true); } },
			{ "-r", "--log-registers", cmdline_arg_type_none,
				"Log Registers",
				[&](std::string s) { return (log_registers = true); } },
			{ "-l", "--log-instructions", cmdline_arg_type_none,
				"Log Instructions",
				[&](std::string s) { return (log_instructions = true); } },
			{ "-h", "--help", cmdline_arg_type_none,
				"Show help",
				[&](std::string s) { return (help_or_error = true); } },
			{ nullptr, nullptr, cmdline_arg_type_none,   nullptr, nullptr }
		};

		auto result = cmdline_option::process_options(options, argc, argv);
		if (!result.second) {
			help_or_error = true;
		} else if (result.first.size() != 1) {
			printf("%s: wrong number of arguments\n", argv[0]);
			help_or_error = true;
		}

		if (help_or_error)
		{
			printf("usage: %s [<options>] <elf_file>\n", argv[0]);
			cmdline_option::print_options(options);
			exit(9);
		}

		filename = result.first[0];
	}

	// print approximate location of host text, heap and stack
	void memory_info(int argc, const char *argv[])
	{
		static const char *textptr = nullptr;
		void *heapptr = malloc(8);
		debug("text : ~0x%016" PRIxPTR, (uintptr_t)&textptr);
		debug("heap : ~0x%016" PRIxPTR, (uintptr_t)heapptr);
		debug("stack: ~0x%016" PRIxPTR, (uintptr_t)argv);
		free(heapptr);
	}

	void exec(int argc, const char *argv[])
	{
		// print process information
		if (memory_debug) {
			memory_info(argc, argv);
		}

		// load ELF (headers only)
		elf.load(filename, true);

		// Processor
		riscv_proc_proxy_rv64 proc;
		proc.flags = emulator_debug ? riscv_processor_flag_emulator_debug : 0;

		// Find the PT_LOAD segments and mmap then into memory
		for (size_t i = 0; i < elf.phdrs.size(); i++) {
			Elf64_Phdr &phdr = elf.phdrs[i];
			if (phdr.p_flags & PT_LOAD) {
				map_load_segment(proc, filename.c_str(), phdr);
			}
		}

		// Map a stack and set the stack pointer
		map_stack(proc, stack_top, stack_size);

		// Set the program counter to the entry address
		proc.pc = elf.ehdr.e_entry;

		// Start the emulator
		rv64_run(proc);

		// Unmap segments
		for (auto &seg: proc.mapped_segments) {
			munmap(seg.first, seg.second);
		}
	}
};

int main(int argc, const char *argv[])
{
	riscv_emulator emulator;
	emulator.parse_commandline(argc, argv);
	emulator.exec(argc, argv);
	return 0;
}
<|endoftext|>