blob: 1a34f2086c797b35b869c588e2780a22f222f880 [file] [log] [blame]
/*
* Copyright 2019 Google Inc.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met: redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer;
* redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution;
* neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef __SIM_GUEST_ABI_VARARGS_HH__
#define __SIM_GUEST_ABI_VARARGS_HH__
#include <memory>
#include <sstream>
#include <type_traits>
#include "sim/guest_abi/definition.hh"
namespace gem5
{
class ThreadContext;
namespace guest_abi
{
/*
* These templates implement a variadic argument mechanism for guest ABI
* functions. A function might be written like this:
*
* void
* func(ThreadContext *tc, VarArgs<Addr, int> varargs)
* {
* warn("Address = %#x, int = %d.",
* varargs.get<Addr>(), varargs.get<int>());
* }
*
* where an object of type VarArgs<...> is its last argument. The types given
* to the template specify what types the function might need to retrieve from
* varargs. The varargs object will then have get<> methods for each of those
* types.
*
* Note that each get<> will happen live. If you modify values through the
* ThreadContext *tc and then run get<>(), you may alter one of your arguments.
* If you're going to use tc to modify state, it would be a good idea to use
* get<>() as soon as possible to avoid corrupting the functions arguments.
*/
// A recursive template which defines virtual functions to retrieve each of the
// requested types. This provides the ABI agnostic interface the function uses.
template <typename ...Types>
class VarArgsBase;
template <typename First, typename ...Types>
class VarArgsBase<First, Types...> : public VarArgsBase<Types...>
{
public:
virtual ~VarArgsBase() = default;
// The virtual function takes a reference parameter so that the different
// _getImpl methods can co-exist through overloading.
virtual void _getImpl(First &) = 0;
// Make sure base class _getImpl-es aren't hidden by this one.
using VarArgsBase<Types...>::_getImpl;
};
// The base case of the recursion.
template <>
class VarArgsBase<>
{
protected:
// This just gives the "using" statement in the non base case something to
// refer to.
void _getImpl();
};
// A recursive template which defines the ABI specific implementation of the
// interface defined above.
//
// The types in Types are consumed one by one, and by
// the time we get down to the base case we'd have lost track of the complete
// set we need to know what interface to inherit. The Base parameter keeps
// track of that through the recursion.
template <typename ABI, typename Base, typename ...Types>
class VarArgsImpl;
template <typename ABI, typename Base, typename First, typename ...Types>
class VarArgsImpl<ABI, Base, First, Types...> :
public VarArgsImpl<ABI, Base, Types...>
{
protected:
// Bring forward the base class constructor.
using VarArgsImpl<ABI, Base, Types...>::VarArgsImpl;
// Make sure base class _getImpl-es don't get hidden by ours.
using VarArgsImpl<ABI, Base, Types...>::_getImpl;
// Implement a version of _getImple, using the ABI specialized version of
// the Argument class.
void
_getImpl(First &first) override
{
first = Argument<ABI, First>::get(this->tc, this->state);
}
};
// The base case of the recursion, which inherits from the interface class.
template <typename ABI, typename Base>
class VarArgsImpl<ABI, Base> : public Base
{
protected:
// Declare state to pass to the Argument<>::get methods.
ThreadContext *tc;
typename ABI::State state;
// Make sure base class _getImpl-es don't get hidden by ours.
using Base::_getImpl;
// Give the "using" statement in our subclass something to refer to.
void _getImpl();
public:
VarArgsImpl(ThreadContext *_tc, const typename ABI::State &_state) :
tc(_tc), state(_state)
{}
};
// A wrapper which provides a nice interface to the virtual functions, and a
// hook for the Argument template mechanism.
template <typename ...Types>
class VarArgs
{
private:
// This points to the implementation which knows how to read arguments
// based on the ABI being used.
std::shared_ptr<VarArgsBase<Types...>> _ptr;
public:
VarArgs(VarArgsBase<Types...> *ptr) : _ptr(ptr) {}
// This template is a friendlier wrapper around the virtual functions the
// raw interface provides. This version lets you pick a type which it then
// returns, instead of having to pre-declare a variable to pass in.
template <typename Arg>
Arg
get()
{
Arg arg;
_ptr->_getImpl(arg);
return arg;
}
};
template <typename T>
struct IsVarArgs : public std::false_type {};
template <typename ...Types>
struct IsVarArgs<VarArgs<Types...>> : public std::true_type {};
template <typename T>
constexpr bool IsVarArgsV = IsVarArgs<T>::value;
template <typename ...Types>
std::ostream &
operator << (std::ostream &os, const VarArgs<Types...> &va)
{
os << "...";
return os;
}
// The ABI independent hook which tells the guest_abi mechanism what to do with
// a VarArgs argument. It constructs the underlying implementation which knows
// about the ABI, and installs it in the VarArgs wrapper to give to the
// function.
template <typename ABI, typename ...Types>
struct Argument<ABI, VarArgs<Types...>>
{
static VarArgs<Types...>
get(ThreadContext *tc, typename ABI::State &state)
{
using Base = VarArgsBase<Types...>;
using Impl = VarArgsImpl<ABI, Base, Types...>;
return VarArgs<Types...>(new Impl(tc, state));
}
};
} // namespace guest_abi
} // namespace gem5
#endif // __SIM_GUEST_ABI_VARARGS_HH__