cxxcall.hpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648
  1. #ifndef __CXXCALL_HPP__
  2. #define __CXXCALL_HPP__ 1
  3. #include "typedesc.hpp"
  4. #include <cstdint>
  5. #include <cstddef>
  6. namespace cxxcall
  7. {
  8. static const size_t WSIZE = sizeof (uintptr_t);
  9. static const size_t WBITS = WSIZE * 8;
  10. struct av_base
  11. {
  12. union fltarg
  13. {
  14. float f;
  15. double d;
  16. long double ld;
  17. };
  18. union twoint
  19. {
  20. long long ll;
  21. struct
  22. {
  23. int u[2];
  24. } i;
  25. };
  26. enum
  27. {
  28. small_struct_ret = 0x1,
  29. gcc_struct_ret = 0x2,
  30. msvc_struct_ret = 0x4,
  31. split_struct_ret = 0x8,
  32. dfl_struct_ret =
  33. #if (defined (CXXCALL_I386) && \
  34. (defined (_WIN32) || defined (__CYGWIN__) || defined (__MACH__) || \
  35. defined (__FreeBSD__)) || defined (__OpenBSD__)) || \
  36. defined (__mipsn32__) || defined (__mips64__) || \
  37. defined (CXXCALL_ARM32) || defined (CXXCALL_ARM64) || \
  38. defined (CXXCALL_AMD64) || (defined (CXXCALL_PPC64) && \
  39. defined (_CALL_ELF) && _CALL_ELF == 2)
  40. small_struct_ret |
  41. #endif
  42. #if defined (__GNUC__) && !(defined (__mipsn32__) || defined (__mips64__))
  43. gcc_struct_ret |
  44. #endif
  45. #if defined (CXXCALL_I386) && defined (_WIN32) && !defined (__CYGWIN__)
  46. msvc_struct_ret |
  47. #endif
  48. 0,
  49. sgi_struct_args = 0x100,
  50. aix_struct_args = 0x200,
  51. dfl_struct_args =
  52. #if defined (__mips__) && !(defined (__mipsn32__) || defined (__mips64__) || \
  53. defined (__GNUC__))
  54. sgi_struct_args |
  55. #endif
  56. #if defined (CXXCALL_PPC32) && defined (_AIX) && !defined (__GNUC__)
  57. aix_struct_args |
  58. #endif
  59. 0,
  60. aix_flt_args = 0x10000,
  61. #if defined (CXXCALL_PPC64) && defined (_AIX) && !defined (__GNUC__)
  62. dfl_flt_args = aix_flt_args,
  63. #else
  64. dfl_flt_args = 0,
  65. #endif
  66. dfl_flags = dfl_struct_ret | dfl_struct_args | dfl_flt_args,
  67. variadic_fn = 1 << 23,
  68. stdcall_fn = 1 << 24,
  69. reg_struct_ret = 1 << 25,
  70. arg_overflow = 1 << 26
  71. };
  72. unsigned int flags;
  73. void *func;
  74. void *raddr;
  75. int rtype;
  76. size_t rsize;
  77. #if defined (CXXCALL_AMD64) && !defined (_WIN32)
  78. static const int IARG_NUM = 6;
  79. static const int FARG_NUM = 8;
  80. unsigned int ianum;
  81. uintptr_t iargs[IARG_NUM];
  82. double fargs[FARG_NUM];
  83. double *fptr;
  84. # define CXXCALL_XINIT_DEFINED
  85. void xinit ()
  86. {
  87. this->ianum = 0;
  88. this->fptr = this->fargs;
  89. }
  90. #endif
  91. #if defined (CXXCALL_MIPS32) && !defined (__mipsn32__) && !defined (__mips64__)
  92. static const int FARG_NUM = 2;
  93. unsigned int anum;
  94. unsigned int fnum;
  95. unsigned int farg_mask;
  96. unsigned int darg_mask;
  97. float fargs[FARG_NUM];
  98. double dargs[FARG_NUM];
  99. # define CXXCALL_XINIT_DEFINED
  100. void xinit ()
  101. {
  102. this->anum = this->fnum = 0;
  103. this->farg_mask = this->darg_mask = 0;
  104. }
  105. #endif
  106. #if defined (__mipsn32__) || defined (__mips64__)
  107. unsigned int anum;
  108. unsigned int farg_mask;
  109. unsigned int darg_mask;
  110. float fargs[8];
  111. # define CXXCALL_XINIT_DEFINED
  112. void xinit ()
  113. {
  114. this->anum = this->farg_mask = this->darg_mask = 0;
  115. }
  116. #endif
  117. #if defined (__armhf__)
  118. static const int IARG_NUM = 4;
  119. uintptr_t *iarg;
  120. unsigned int ianum;
  121. unsigned int fanum;
  122. unsigned int farg_mask;
  123. unsigned int darg_mask;
  124. float fargs[16];
  125. double dargs[8];
  126. # define CXXCALL_XINIT_DEFINED
  127. void xinit ()
  128. {
  129. this->ianum = this->fanum = 0;
  130. this->farg_mask = this->darg_mask = 0;
  131. }
  132. #endif
  133. #if defined (CXXCALL_ARM64)
  134. static const int IARG_NUM = 8;
  135. static const int FARG_NUM = 8;
  136. unsigned int ianum;
  137. uintptr_t iargs[IARG_NUM];
  138. unsigned int fanum;
  139. unsigned char farg_types[FARG_NUM];
  140. fltarg fargs[FARG_NUM];
  141. # define CXXCALL_XINIT_DEFINED
  142. void xinit ()
  143. {
  144. this->ianum = this->fanum = 0;
  145. }
  146. #endif
  147. #if defined (CXXCALL_PPC32) || defined (CXXCALL_PPC64)
  148. # if defined (_AIX) || (defined (__MACH__) && defined (__APPLE__))
  149. static const int FARG_NUM = 13;
  150. # else
  151. static const int FARG_NUM = 8;
  152. static const int IARG_NUM = 8;
  153. unsigned int ianum;
  154. uintptr_t iargs[IARG_NUM];
  155. # endif
  156. double fargs[FARG_NUM];
  157. double *fptr;
  158. # define CXXCALL_XINIT_DEFINED
  159. void xinit ()
  160. {
  161. #if !(defined (_AIX) || (defined (__MACH__) && defined (__APPLE__)))
  162. this->ianum = 0;
  163. #endif
  164. this->fptr = this->fargs;
  165. }
  166. #endif
  167. #if defined (CXXCALL_AMD64) && defined (_WIN32)
  168. static const int FARG_NUM = 4;
  169. unsigned int anum;
  170. unsigned int fnum;
  171. double fargs[FARG_NUM];
  172. # define CXXCALL_XINIT_DEFINED
  173. void xinit ()
  174. {
  175. this->anum = this->fanum = 0;
  176. }
  177. #endif
  178. #ifndef CXXCALL_XINIT_DEFINED
  179. void xinit () {}
  180. #endif
  181. #undef CXXCALL_XINIT_DEFINED
  182. };
  183. struct alignas (std::max_align_t) av_data : public av_base
  184. {
  185. uintptr_t *args;
  186. uintptr_t *curp;
  187. uintptr_t *endp;
  188. void _Reg_struct_ret ();
  189. void init (uintptr_t *argp, size_t nargs, void *fct,
  190. void *retaddr, int rettype, size_t retsize, unsigned int flg)
  191. {
  192. this->xinit ();
  193. this->args = this->curp = argp;
  194. this->endp = this->args + nargs;
  195. this->func = (void *)fct;
  196. this->raddr = retaddr;
  197. this->rtype = rettype;
  198. this->rsize = retsize;
  199. this->flags = flg;
  200. if (rettype == type::struct_t &&
  201. (this->flags & small_struct_ret))
  202. this->_Reg_struct_ret ();
  203. #ifdef __armhf__
  204. this->curp += IARG_NUM;
  205. #endif
  206. }
  207. bool set_overflow ()
  208. {
  209. this->flags |= arg_overflow;
  210. return (false);
  211. }
  212. bool arg_t (intptr_t val);
  213. bool arg_ut (uintptr_t val)
  214. {
  215. return (this->arg_t ((intptr_t)val));
  216. }
  217. bool arg (float val);
  218. bool arg (double val);
  219. bool arg (long double val)
  220. #ifdef CXXCALL_LONG_DOUBLE_ALIASED
  221. {
  222. return (this->arg ((double)val));
  223. }
  224. #else
  225. ;
  226. #endif
  227. #define ARG_(type, suffix) \
  228. bool arg (type val) \
  229. { \
  230. return (this->arg_##suffix (val)); \
  231. }
  232. ARG_(signed char, t)
  233. ARG_(unsigned char, ut)
  234. ARG_(short, t)
  235. ARG_(unsigned short, ut)
  236. ARG_(int, t)
  237. ARG_(unsigned int, ut)
  238. ARG_(long, t)
  239. ARG_(unsigned long, ut)
  240. #ifdef CXXCALL_WIDE
  241. ARG_(long long, t)
  242. ARG_(unsigned long long, ut)
  243. #else
  244. bool arg (long long val);
  245. bool arg (unsigned long long val)
  246. {
  247. return (this->arg ((long long)val));
  248. }
  249. #endif
  250. #undef ARG_
  251. bool arg (const void *ptr)
  252. {
  253. return (this->arg ((uintptr_t)ptr));
  254. }
  255. bool arg (const void *data, size_t size, size_t align);
  256. bool call ();
  257. bool error () const
  258. {
  259. return ((this->flags & arg_overflow) != 0);
  260. }
  261. };
  262. struct cb_data : public av_base
  263. {
  264. union
  265. {
  266. signed char sch;
  267. unsigned char uch;
  268. short shrt;
  269. unsigned short ushrt;
  270. int ival;
  271. unsigned int uival;
  272. long lval;
  273. unsigned long ulval;
  274. long long llval;
  275. unsigned long long ullval;
  276. twoint parts;
  277. double dbl;
  278. float flt;
  279. long double ldbl;
  280. } tmp;
  281. uintptr_t curr;
  282. #if defined (CXXCALL_I386) || defined (CXXCALL_ARM64)
  283. void *structaddr;
  284. #endif
  285. #if defined (CXXCALL_MIPS) && !defined (__mipsn32__) && !defined (__mips64__)
  286. uintptr_t memarg;
  287. #endif
  288. bool _Reg_struct_ret ();
  289. void init (unsigned int flg, int rettype)
  290. {
  291. this->xinit ();
  292. this->flags = flg;
  293. if ((this->rtype = rettype) == type::struct_t &&
  294. (this->flags & small_struct_ret) &&
  295. this->_Reg_struct_ret ())
  296. {
  297. this->raddr = &this->tmp;
  298. this->flags |= reg_struct_ret;
  299. }
  300. }
  301. template <class T>
  302. void start (unsigned int flg = dfl_flags)
  303. {
  304. this->init (flg, typedesc<T>::code);
  305. }
  306. static size_t arg_size (size_t size)
  307. {
  308. return ((size + WSIZE - 1) & ~(WSIZE - 1));
  309. }
  310. static size_t struct_alignment (size_t align)
  311. {
  312. #if defined (_WIN32) && defined (CXXCALL_I386)
  313. return (align <= 4 ? align : 4);
  314. #else
  315. return (align);
  316. #endif
  317. }
  318. void* xarg (size_t size, size_t align, bool integral, bool on_stack);
  319. void* arg (size_t size, size_t align, bool on_stack)
  320. {
  321. return (this->xarg (size, align, false, on_stack));
  322. }
  323. template <class T>
  324. T arg ()
  325. {
  326. return (*(T *)this->xarg (sizeof (T), alignof (T), true, false));
  327. }
  328. #ifndef CXXCALL_WIDE
  329. long long arg_ll ();
  330. #endif
  331. float arg_f ();
  332. double arg_d ();
  333. #ifdef CXXCALL_LONG_DOUBLE_ALIASED
  334. long double arg_ld ()
  335. {
  336. return (this->arg_d ());
  337. }
  338. #else
  339. long double arg_ld ();
  340. #endif
  341. void _Assert_rtype (int);
  342. void ret ()
  343. {
  344. this->_Assert_rtype (type::void_t);
  345. }
  346. template <class T>
  347. void ret (const T& val)
  348. {
  349. int type = typedesc<T>::code;
  350. this->_Assert_rtype (type);
  351. void *ptr = type == type::struct_t ? this->raddr : &this->tmp;
  352. *(T *)ptr = val;
  353. }
  354. static void* alloc (void (*fct) (cb_data *, void *), void *arg);
  355. static void dealloc (void *mem);
  356. static void fill (void *outp, void (*fct) (cb_data *, void *), void *arg);
  357. };
  358. #ifndef CXXCALL_WIDE
  359. template <>
  360. inline long long cb_data::arg<long long> ()
  361. {
  362. return (this->arg_ll ());
  363. }
  364. template <>
  365. inline unsigned long long cb_data::arg<unsigned long long> ()
  366. {
  367. return ((unsigned long long)this->arg_ll ());
  368. }
  369. #endif
  370. template <>
  371. inline void* cb_data::arg<void *> ()
  372. {
  373. return ((void *)this->arg<uintptr_t> ());
  374. }
  375. template <>
  376. inline float cb_data::arg<float> ()
  377. {
  378. return (this->arg_f ());
  379. }
  380. template <>
  381. inline double cb_data::arg<double> ()
  382. {
  383. return (this->arg_d ());
  384. }
  385. template <>
  386. inline long double cb_data::arg<long double> ()
  387. {
  388. return (this->arg_ld ());
  389. }
  390. /* Determine if a structure is 'splittable'; i.e: if its contents may
  391. * be returned in more than 1 register. */
  392. template <class T, class M1>
  393. bool splittable_p (M1 T::*)
  394. {
  395. return ((sizeof (M1) - 1) / WSIZE == 0);
  396. }
  397. template <class T1, class T2>
  398. constexpr size_t _Offsetof2 ()
  399. {
  400. return ((sizeof (T1) + alignof (T2) - 1) & -(long)alignof (T2));
  401. }
  402. template <class T, class M1, class M2>
  403. bool splittable_p (M1 T::*m1, M2 T::*)
  404. {
  405. return (splittable_p (m1) &&
  406. (_Offsetof2<M1, M2> / WSIZE ==
  407. (_Offsetof2<M1, M2> + sizeof (M2) - 1) / WSIZE));
  408. }
  409. template <class T1, class T2, class T3>
  410. constexpr size_t _Offsetof3 ()
  411. {
  412. return ((_Offsetof2<T1, T2> + alignof (T3)) & -(long)alignof (T3));
  413. }
  414. template <class T, class M1, class M2, class M3>
  415. bool splittable_p (M1 T::*m1, M2 T::*m2, M3 T::*)
  416. {
  417. return (splittable_p (m1, m2) &&
  418. (_Offsetof3<M1, M2, M3> / WSIZE ==
  419. (_Offsetof3<M1, M2, M3> + sizeof (M3) - 1) / WSIZE));
  420. }
  421. template <class T1, class T2, class T3, class T4>
  422. constexpr size_t _Offsetof4 ()
  423. {
  424. return ((_Offsetof2<T1, T2, T3> + alignof (T4)) & -(long)alignof (T4));
  425. }
  426. template <class T, class M1, class M2, class M3, class M4>
  427. bool splittable_p (M1 T::*m1, M2 T::*m2, M3 T::*m3, M4 T::*)
  428. {
  429. return (splittable_p (m1, m2, m3) &&
  430. (_Offsetof4<M1, M2, M3, M4> / WSIZE ==
  431. (_Offsetof4<M1, M2, M3, M4> + sizeof (M4) - 1) / WSIZE));
  432. }
  433. // Like 'enable_if', but don't pull <type_traits> for it.
  434. template <bool B>
  435. struct enable
  436. {
  437. };
  438. template <>
  439. struct enable<true>
  440. {
  441. typedef int type;
  442. };
  443. template <class T, size_t N>
  444. struct av_static
  445. {
  446. typedef typename typedesc<T>::rtype rtype;
  447. rtype retval;
  448. uintptr_t st_args[N];
  449. av_data av;
  450. av_static (void *fn, unsigned int flg)
  451. {
  452. this->av.init (this->st_args, N, fn, &this->retval,
  453. typedesc<T>::code, sizeof (this->retval), flg);
  454. }
  455. template <class T2>
  456. bool arg (T2 value)
  457. {
  458. return (this->av.arg (value));
  459. }
  460. template <class T2>
  461. bool arg (const T2& val,
  462. typename enable<typedesc<T2>::code == type::struct_t>::type = 0)
  463. {
  464. return (this->av.arg (&val, sizeof (val), alignof (T2)));
  465. }
  466. bool error () const
  467. {
  468. return (this->av.error ());
  469. }
  470. rtype call ()
  471. {
  472. this->av.call ();
  473. return (this->retval);
  474. }
  475. };
  476. template <size_t S1, size_t ...SN>
  477. struct slot_sum
  478. {
  479. static const size_t nslots = S1 + slot_sum<SN...>::nslots;
  480. };
  481. template <size_t S1>
  482. struct slot_sum<S1>
  483. {
  484. static const size_t nslots = S1;
  485. };
  486. #ifdef __armhf__
  487. # define CXXCALL_ESLOTS 4
  488. #else
  489. # define CXXCALL_ESLOTS 0
  490. #endif
  491. #define CXXCALL_SLOTS1(T) typedesc<T>::nslots + CXXCALL_ESLOTS
  492. #define CXXCALL_VSLOTS(T) \
  493. slot_sum<typedesc<T>::nslots...>::nslots + CXXCALL_ESLOTS
  494. template <class T>
  495. auto make_av_static (T (*fn) (), unsigned int flg = av_data::dfl_flags) ->
  496. decltype (av_static<T, CXXCALL_SLOTS1 (T)> (0, 0))
  497. {
  498. av_static<T, CXXCALL_SLOTS1 (T)> ret ((void *)fn, flg);
  499. return (ret);
  500. }
  501. template <class T, class ...Args>
  502. auto make_av_static (T (*fn) (Args...),
  503. unsigned int flg = av_data::dfl_flags) ->
  504. decltype (av_static<T, CXXCALL_VSLOTS (Args)> (0, 0))
  505. {
  506. av_static<T, CXXCALL_VSLOTS (Args)> ret ((void *)fn, flg);
  507. return (ret);
  508. }
  509. template <class T, class ...Args>
  510. auto make_av_static (T (*fn) (Args..., ...),
  511. unsigned int flg = av_data::dfl_flags) ->
  512. decltype (av_static<T, CXXCALL_VSLOTS (Args)> (0, 0))
  513. {
  514. av_static<T, CXXCALL_VSLOTS (Args)>
  515. ret ((void *)fn, flg | av_data::variadic_fn);
  516. return (ret);
  517. }
  518. #undef CXXCALL_ESLOTS
  519. #undef CXXCALL_SLOTS1
  520. #undef CXXCALL_VSLOTS
  521. } // namespace cxxcall
  522. #endif