123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648 |
- #ifndef __CXXCALL_HPP__
- #define __CXXCALL_HPP__ 1
- #include "typedesc.hpp"
- #include <cstdint>
- #include <cstddef>
- namespace cxxcall
- {
- static const size_t WSIZE = sizeof (uintptr_t);
- static const size_t WBITS = WSIZE * 8;
- struct av_base
- {
- union fltarg
- {
- float f;
- double d;
- long double ld;
- };
- union twoint
- {
- long long ll;
- struct
- {
- int u[2];
- } i;
- };
- enum
- {
- small_struct_ret = 0x1,
- gcc_struct_ret = 0x2,
- msvc_struct_ret = 0x4,
- split_struct_ret = 0x8,
- dfl_struct_ret =
- #if (defined (CXXCALL_I386) && \
- (defined (_WIN32) || defined (__CYGWIN__) || defined (__MACH__) || \
- defined (__FreeBSD__)) || defined (__OpenBSD__)) || \
- defined (__mipsn32__) || defined (__mips64__) || \
- defined (CXXCALL_ARM32) || defined (CXXCALL_ARM64) || \
- defined (CXXCALL_AMD64) || (defined (CXXCALL_PPC64) && \
- defined (_CALL_ELF) && _CALL_ELF == 2)
- small_struct_ret |
- #endif
- #if defined (__GNUC__) && !(defined (__mipsn32__) || defined (__mips64__))
- gcc_struct_ret |
- #endif
- #if defined (CXXCALL_I386) && defined (_WIN32) && !defined (__CYGWIN__)
- msvc_struct_ret |
- #endif
- 0,
- sgi_struct_args = 0x100,
- aix_struct_args = 0x200,
- dfl_struct_args =
- #if defined (__mips__) && !(defined (__mipsn32__) || defined (__mips64__) || \
- defined (__GNUC__))
- sgi_struct_args |
- #endif
- #if defined (CXXCALL_PPC32) && defined (_AIX) && !defined (__GNUC__)
- aix_struct_args |
- #endif
- 0,
- aix_flt_args = 0x10000,
- #if defined (CXXCALL_PPC64) && defined (_AIX) && !defined (__GNUC__)
- dfl_flt_args = aix_flt_args,
- #else
- dfl_flt_args = 0,
- #endif
- dfl_flags = dfl_struct_ret | dfl_struct_args | dfl_flt_args,
- variadic_fn = 1 << 23,
- stdcall_fn = 1 << 24,
- reg_struct_ret = 1 << 25,
- arg_overflow = 1 << 26
- };
- unsigned int flags;
- void *func;
- void *raddr;
- int rtype;
- size_t rsize;
- #if defined (CXXCALL_AMD64) && !defined (_WIN32)
- static const int IARG_NUM = 6;
- static const int FARG_NUM = 8;
- unsigned int ianum;
- uintptr_t iargs[IARG_NUM];
- double fargs[FARG_NUM];
- double *fptr;
- # define CXXCALL_XINIT_DEFINED
- void xinit ()
- {
- this->ianum = 0;
- this->fptr = this->fargs;
- }
- #endif
- #if defined (CXXCALL_MIPS32) && !defined (__mipsn32__) && !defined (__mips64__)
- static const int FARG_NUM = 2;
- unsigned int anum;
- unsigned int fnum;
- unsigned int farg_mask;
- unsigned int darg_mask;
- float fargs[FARG_NUM];
- double dargs[FARG_NUM];
- # define CXXCALL_XINIT_DEFINED
- void xinit ()
- {
- this->anum = this->fnum = 0;
- this->farg_mask = this->darg_mask = 0;
- }
- #endif
- #if defined (__mipsn32__) || defined (__mips64__)
- unsigned int anum;
- unsigned int farg_mask;
- unsigned int darg_mask;
- float fargs[8];
- # define CXXCALL_XINIT_DEFINED
- void xinit ()
- {
- this->anum = this->farg_mask = this->darg_mask = 0;
- }
- #endif
- #if defined (__armhf__)
- static const int IARG_NUM = 4;
- uintptr_t *iarg;
- unsigned int ianum;
- unsigned int fanum;
- unsigned int farg_mask;
- unsigned int darg_mask;
- float fargs[16];
- double dargs[8];
- # define CXXCALL_XINIT_DEFINED
- void xinit ()
- {
- this->ianum = this->fanum = 0;
- this->farg_mask = this->darg_mask = 0;
- }
- #endif
- #if defined (CXXCALL_ARM64)
- static const int IARG_NUM = 8;
- static const int FARG_NUM = 8;
- unsigned int ianum;
- uintptr_t iargs[IARG_NUM];
- unsigned int fanum;
- unsigned char farg_types[FARG_NUM];
- fltarg fargs[FARG_NUM];
- # define CXXCALL_XINIT_DEFINED
- void xinit ()
- {
- this->ianum = this->fanum = 0;
- }
- #endif
- #if defined (CXXCALL_PPC32) || defined (CXXCALL_PPC64)
- # if defined (_AIX) || (defined (__MACH__) && defined (__APPLE__))
- static const int FARG_NUM = 13;
- # else
- static const int FARG_NUM = 8;
- static const int IARG_NUM = 8;
- unsigned int ianum;
- uintptr_t iargs[IARG_NUM];
- # endif
- double fargs[FARG_NUM];
- double *fptr;
- # define CXXCALL_XINIT_DEFINED
- void xinit ()
- {
- #if !(defined (_AIX) || (defined (__MACH__) && defined (__APPLE__)))
- this->ianum = 0;
- #endif
- this->fptr = this->fargs;
- }
- #endif
- #if defined (CXXCALL_AMD64) && defined (_WIN32)
- static const int FARG_NUM = 4;
- unsigned int anum;
- unsigned int fnum;
- double fargs[FARG_NUM];
- # define CXXCALL_XINIT_DEFINED
- void xinit ()
- {
- this->anum = this->fanum = 0;
- }
- #endif
- #ifndef CXXCALL_XINIT_DEFINED
- void xinit () {}
- #endif
- #undef CXXCALL_XINIT_DEFINED
- };
- struct alignas (std::max_align_t) av_data : public av_base
- {
- uintptr_t *args;
- uintptr_t *curp;
- uintptr_t *endp;
- void _Reg_struct_ret ();
- void init (uintptr_t *argp, size_t nargs, void *fct,
- void *retaddr, int rettype, size_t retsize, unsigned int flg)
- {
- this->xinit ();
- this->args = this->curp = argp;
- this->endp = this->args + nargs;
- this->func = (void *)fct;
- this->raddr = retaddr;
- this->rtype = rettype;
- this->rsize = retsize;
- this->flags = flg;
- if (rettype == type::struct_t &&
- (this->flags & small_struct_ret))
- this->_Reg_struct_ret ();
- #ifdef __armhf__
- this->curp += IARG_NUM;
- #endif
- }
- bool set_overflow ()
- {
- this->flags |= arg_overflow;
- return (false);
- }
- bool arg_t (intptr_t val);
- bool arg_ut (uintptr_t val)
- {
- return (this->arg_t ((intptr_t)val));
- }
- bool arg (float val);
- bool arg (double val);
- bool arg (long double val)
- #ifdef CXXCALL_LONG_DOUBLE_ALIASED
- {
- return (this->arg ((double)val));
- }
- #else
- ;
- #endif
- #define ARG_(type, suffix) \
- bool arg (type val) \
- { \
- return (this->arg_##suffix (val)); \
- }
- ARG_(signed char, t)
- ARG_(unsigned char, ut)
- ARG_(short, t)
- ARG_(unsigned short, ut)
- ARG_(int, t)
- ARG_(unsigned int, ut)
- ARG_(long, t)
- ARG_(unsigned long, ut)
- #ifdef CXXCALL_WIDE
- ARG_(long long, t)
- ARG_(unsigned long long, ut)
- #else
- bool arg (long long val);
- bool arg (unsigned long long val)
- {
- return (this->arg ((long long)val));
- }
- #endif
- #undef ARG_
- bool arg (const void *ptr)
- {
- return (this->arg ((uintptr_t)ptr));
- }
- bool arg (const void *data, size_t size, size_t align);
- bool call ();
- bool error () const
- {
- return ((this->flags & arg_overflow) != 0);
- }
- };
- struct cb_data : public av_base
- {
- union
- {
- signed char sch;
- unsigned char uch;
- short shrt;
- unsigned short ushrt;
- int ival;
- unsigned int uival;
- long lval;
- unsigned long ulval;
- long long llval;
- unsigned long long ullval;
- twoint parts;
- double dbl;
- float flt;
- long double ldbl;
- } tmp;
- uintptr_t curr;
- #if defined (CXXCALL_I386) || defined (CXXCALL_ARM64)
- void *structaddr;
- #endif
- #if defined (CXXCALL_MIPS) && !defined (__mipsn32__) && !defined (__mips64__)
- uintptr_t memarg;
- #endif
- bool _Reg_struct_ret ();
- void init (unsigned int flg, int rettype)
- {
- this->xinit ();
- this->flags = flg;
- if ((this->rtype = rettype) == type::struct_t &&
- (this->flags & small_struct_ret) &&
- this->_Reg_struct_ret ())
- {
- this->raddr = &this->tmp;
- this->flags |= reg_struct_ret;
- }
- }
- template <class T>
- void start (unsigned int flg = dfl_flags)
- {
- this->init (flg, typedesc<T>::code);
- }
- static size_t arg_size (size_t size)
- {
- return ((size + WSIZE - 1) & ~(WSIZE - 1));
- }
- static size_t struct_alignment (size_t align)
- {
- #if defined (_WIN32) && defined (CXXCALL_I386)
- return (align <= 4 ? align : 4);
- #else
- return (align);
- #endif
- }
- void* xarg (size_t size, size_t align, bool integral, bool on_stack);
- void* arg (size_t size, size_t align, bool on_stack)
- {
- return (this->xarg (size, align, false, on_stack));
- }
- template <class T>
- T arg ()
- {
- return (*(T *)this->xarg (sizeof (T), alignof (T), true, false));
- }
- #ifndef CXXCALL_WIDE
- long long arg_ll ();
- #endif
- float arg_f ();
- double arg_d ();
- #ifdef CXXCALL_LONG_DOUBLE_ALIASED
- long double arg_ld ()
- {
- return (this->arg_d ());
- }
- #else
- long double arg_ld ();
- #endif
- void _Assert_rtype (int);
- void ret ()
- {
- this->_Assert_rtype (type::void_t);
- }
- template <class T>
- void ret (const T& val)
- {
- int type = typedesc<T>::code;
- this->_Assert_rtype (type);
- void *ptr = type == type::struct_t ? this->raddr : &this->tmp;
- *(T *)ptr = val;
- }
- static void* alloc (void (*fct) (cb_data *, void *), void *arg);
- static void dealloc (void *mem);
- static void fill (void *outp, void (*fct) (cb_data *, void *), void *arg);
- };
- #ifndef CXXCALL_WIDE
- template <>
- inline long long cb_data::arg<long long> ()
- {
- return (this->arg_ll ());
- }
- template <>
- inline unsigned long long cb_data::arg<unsigned long long> ()
- {
- return ((unsigned long long)this->arg_ll ());
- }
- #endif
- template <>
- inline void* cb_data::arg<void *> ()
- {
- return ((void *)this->arg<uintptr_t> ());
- }
- template <>
- inline float cb_data::arg<float> ()
- {
- return (this->arg_f ());
- }
- template <>
- inline double cb_data::arg<double> ()
- {
- return (this->arg_d ());
- }
- template <>
- inline long double cb_data::arg<long double> ()
- {
- return (this->arg_ld ());
- }
- /* Determine if a structure is 'splittable'; i.e: if its contents may
- * be returned in more than 1 register. */
- template <class T, class M1>
- bool splittable_p (M1 T::*)
- {
- return ((sizeof (M1) - 1) / WSIZE == 0);
- }
- template <class T1, class T2>
- constexpr size_t _Offsetof2 ()
- {
- return ((sizeof (T1) + alignof (T2) - 1) & -(long)alignof (T2));
- }
- template <class T, class M1, class M2>
- bool splittable_p (M1 T::*m1, M2 T::*)
- {
- return (splittable_p (m1) &&
- (_Offsetof2<M1, M2> / WSIZE ==
- (_Offsetof2<M1, M2> + sizeof (M2) - 1) / WSIZE));
- }
- template <class T1, class T2, class T3>
- constexpr size_t _Offsetof3 ()
- {
- return ((_Offsetof2<T1, T2> + alignof (T3)) & -(long)alignof (T3));
- }
- template <class T, class M1, class M2, class M3>
- bool splittable_p (M1 T::*m1, M2 T::*m2, M3 T::*)
- {
- return (splittable_p (m1, m2) &&
- (_Offsetof3<M1, M2, M3> / WSIZE ==
- (_Offsetof3<M1, M2, M3> + sizeof (M3) - 1) / WSIZE));
- }
- template <class T1, class T2, class T3, class T4>
- constexpr size_t _Offsetof4 ()
- {
- return ((_Offsetof2<T1, T2, T3> + alignof (T4)) & -(long)alignof (T4));
- }
- template <class T, class M1, class M2, class M3, class M4>
- bool splittable_p (M1 T::*m1, M2 T::*m2, M3 T::*m3, M4 T::*)
- {
- return (splittable_p (m1, m2, m3) &&
- (_Offsetof4<M1, M2, M3, M4> / WSIZE ==
- (_Offsetof4<M1, M2, M3, M4> + sizeof (M4) - 1) / WSIZE));
- }
- // Like 'enable_if', but don't pull <type_traits> for it.
- template <bool B>
- struct enable
- {
- };
- template <>
- struct enable<true>
- {
- typedef int type;
- };
- template <class T, size_t N>
- struct av_static
- {
- typedef typename typedesc<T>::rtype rtype;
- rtype retval;
- uintptr_t st_args[N];
- av_data av;
- av_static (void *fn, unsigned int flg)
- {
- this->av.init (this->st_args, N, fn, &this->retval,
- typedesc<T>::code, sizeof (this->retval), flg);
- }
- template <class T2>
- bool arg (T2 value)
- {
- return (this->av.arg (value));
- }
- template <class T2>
- bool arg (const T2& val,
- typename enable<typedesc<T2>::code == type::struct_t>::type = 0)
- {
- return (this->av.arg (&val, sizeof (val), alignof (T2)));
- }
- bool error () const
- {
- return (this->av.error ());
- }
- rtype call ()
- {
- this->av.call ();
- return (this->retval);
- }
- };
- template <size_t S1, size_t ...SN>
- struct slot_sum
- {
- static const size_t nslots = S1 + slot_sum<SN...>::nslots;
- };
- template <size_t S1>
- struct slot_sum<S1>
- {
- static const size_t nslots = S1;
- };
- #ifdef __armhf__
- # define CXXCALL_ESLOTS 4
- #else
- # define CXXCALL_ESLOTS 0
- #endif
- #define CXXCALL_SLOTS1(T) typedesc<T>::nslots + CXXCALL_ESLOTS
- #define CXXCALL_VSLOTS(T) \
- slot_sum<typedesc<T>::nslots...>::nslots + CXXCALL_ESLOTS
- template <class T>
- auto make_av_static (T (*fn) (), unsigned int flg = av_data::dfl_flags) ->
- decltype (av_static<T, CXXCALL_SLOTS1 (T)> (0, 0))
- {
- av_static<T, CXXCALL_SLOTS1 (T)> ret ((void *)fn, flg);
- return (ret);
- }
- template <class T, class ...Args>
- auto make_av_static (T (*fn) (Args...),
- unsigned int flg = av_data::dfl_flags) ->
- decltype (av_static<T, CXXCALL_VSLOTS (Args)> (0, 0))
- {
- av_static<T, CXXCALL_VSLOTS (Args)> ret ((void *)fn, flg);
- return (ret);
- }
- template <class T, class ...Args>
- auto make_av_static (T (*fn) (Args..., ...),
- unsigned int flg = av_data::dfl_flags) ->
- decltype (av_static<T, CXXCALL_VSLOTS (Args)> (0, 0))
- {
- av_static<T, CXXCALL_VSLOTS (Args)>
- ret ((void *)fn, flg | av_data::variadic_fn);
- return (ret);
- }
- #undef CXXCALL_ESLOTS
- #undef CXXCALL_SLOTS1
- #undef CXXCALL_VSLOTS
- } // namespace cxxcall
- #endif
|