gsubr.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380
  1. /* Copyright (C) 1995-2001, 2006, 2008-2011, 2013, 2015
  2. * Free Software Foundation, Inc.
  3. *
  4. * This library is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU Lesser General Public License
  6. * as published by the Free Software Foundation; either version 3 of
  7. * the License, or (at your option) any later version.
  8. *
  9. * This library is distributed in the hope that it will be useful, but
  10. * WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * Lesser General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU Lesser General Public
  15. * License along with this library; if not, write to the Free Software
  16. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  17. * 02110-1301 USA
  18. */
  19. #ifdef HAVE_CONFIG_H
  20. # include <config.h>
  21. #endif
  22. #include <stdio.h>
  23. #include <stdarg.h>
  24. #include "libguile/_scm.h"
  25. #include "libguile/gsubr.h"
  26. #include "libguile/foreign.h"
  27. #include "libguile/instructions.h"
  28. #include "libguile/srfi-4.h"
  29. #include "libguile/programs.h"
  30. #include "libguile/private-options.h"
  31. /*
  32. * gsubr.c
  33. * Provide `gsubrs' -- subrs taking a prescribed number of required, optional,
  34. * and rest arguments.
  35. */
  36. /* OK here goes nothing: we're going to define VM assembly trampolines for
  37. invoking subrs. Ready? Right! */
  38. /* There's a maximum of 10 args, so the number of possible combinations is:
  39. (REQ-OPT-REST)
  40. for 0 args: 1 (000) (1 + 0)
  41. for 1 arg: 3 (100, 010, 001) (2 + 1)
  42. for 2 args: 5 (200, 110, 020, 101, 011) (3 + 2)
  43. for 3 args: 7 (300, 210, 120, 030, 201, 111, 021) (4 + 3)
  44. for N args: 2N+1
  45. and the index at which N args starts:
  46. for 0 args: 0
  47. for 1 args: 1
  48. for 2 args: 4
  49. for 3 args: 9
  50. for N args: N^2
  51. One can prove this:
  52. (1 + 3 + 5 + ... + (2N+1))
  53. = ((2N+1)+1)/2 * (N+1)
  54. = 2(N+1)/2 * (N+1)
  55. = (N+1)^2
  56. Thus the total sum is 11^2 = 121. Let's just generate all of them as
  57. read-only data.
  58. */
  59. /* A: req; B: opt; C: rest */
  60. #define A(nreq) \
  61. SCM_PACK_OP_24 (assert_nargs_ee, nreq + 1), \
  62. SCM_PACK_OP_24 (subr_call, 0), \
  63. SCM_PACK_OP_24 (handle_interrupts, 0), \
  64. SCM_PACK_OP_24 (return_values, 0), \
  65. 0, \
  66. 0
  67. #define B(nopt) \
  68. SCM_PACK_OP_24 (assert_nargs_le, nopt + 1), \
  69. SCM_PACK_OP_24 (alloc_frame, nopt + 1), \
  70. SCM_PACK_OP_24 (subr_call, 0), \
  71. SCM_PACK_OP_24 (handle_interrupts, 0), \
  72. SCM_PACK_OP_24 (return_values, 0), \
  73. 0
  74. #define C() \
  75. SCM_PACK_OP_24 (bind_rest, 1), \
  76. SCM_PACK_OP_24 (subr_call, 0), \
  77. SCM_PACK_OP_24 (handle_interrupts, 0), \
  78. SCM_PACK_OP_24 (return_values, 0), \
  79. 0, \
  80. 0
  81. #define AB(nreq, nopt) \
  82. SCM_PACK_OP_24 (assert_nargs_ge, nreq + 1), \
  83. SCM_PACK_OP_24 (assert_nargs_le, nreq + nopt + 1), \
  84. SCM_PACK_OP_24 (alloc_frame, nreq + nopt + 1), \
  85. SCM_PACK_OP_24 (subr_call, 0), \
  86. SCM_PACK_OP_24 (handle_interrupts, 0), \
  87. SCM_PACK_OP_24 (return_values, 0)
  88. #define AC(nreq) \
  89. SCM_PACK_OP_24 (assert_nargs_ge, nreq + 1), \
  90. SCM_PACK_OP_24 (bind_rest, nreq + 1), \
  91. SCM_PACK_OP_24 (subr_call, 0), \
  92. SCM_PACK_OP_24 (handle_interrupts, 0), \
  93. SCM_PACK_OP_24 (return_values, 0), \
  94. 0
  95. #define BC(nopt) \
  96. SCM_PACK_OP_24 (bind_rest, nopt + 1), \
  97. SCM_PACK_OP_24 (subr_call, 0), \
  98. SCM_PACK_OP_24 (handle_interrupts, 0), \
  99. SCM_PACK_OP_24 (return_values, 0), \
  100. 0, \
  101. 0
  102. #define ABC(nreq, nopt) \
  103. SCM_PACK_OP_24 (assert_nargs_ge, nreq + 1), \
  104. SCM_PACK_OP_24 (bind_rest, nreq + nopt + 1), \
  105. SCM_PACK_OP_24 (subr_call, 0), \
  106. SCM_PACK_OP_24 (handle_interrupts, 0), \
  107. SCM_PACK_OP_24 (return_values, 0), \
  108. 0
  109. /*
  110. (defun generate-bytecode (n)
  111. "Generate bytecode for N arguments"
  112. (interactive "p")
  113. (insert (format "/\* %d arguments *\/\n " n))
  114. (let ((nreq n))
  115. (while (<= 0 nreq)
  116. (let ((nopt (- n nreq)))
  117. (insert
  118. (if (< 0 nreq)
  119. (if (< 0 nopt)
  120. (format " AB(%d,%d)," nreq nopt)
  121. (format " A(%d)," nreq))
  122. (if (< 0 nopt)
  123. (format " B(%d)," nopt)
  124. (format " A(0),"))))
  125. (setq nreq (1- nreq))))
  126. (insert "\n ")
  127. (setq nreq (1- n))
  128. (while (<= 0 nreq)
  129. (let ((nopt (- n nreq 1)))
  130. (insert
  131. (if (< 0 nreq)
  132. (if (< 0 nopt)
  133. (format " ABC(%d,%d)," nreq nopt)
  134. (format " AC(%d)," nreq))
  135. (if (< 0 nopt)
  136. (format " BC(%d)," nopt)
  137. (format " C(),"))))
  138. (setq nreq (1- nreq))))
  139. (insert "\n\n ")))
  140. (defun generate-bytecodes (n)
  141. "Generate bytecodes for up to N arguments"
  142. (interactive "p")
  143. (let ((i 0))
  144. (while (<= i n)
  145. (generate-bytecode i)
  146. (setq i (1+ i)))))
  147. */
  148. static const scm_t_uint32 subr_stub_code[] = {
  149. /* C-u 1 0 M-x generate-bytecodes RET */
  150. /* 0 arguments */
  151. A(0),
  152. /* 1 arguments */
  153. A(1), B(1),
  154. C(),
  155. /* 2 arguments */
  156. A(2), AB(1,1), B(2),
  157. AC(1), BC(1),
  158. /* 3 arguments */
  159. A(3), AB(2,1), AB(1,2), B(3),
  160. AC(2), ABC(1,1), BC(2),
  161. /* 4 arguments */
  162. A(4), AB(3,1), AB(2,2), AB(1,3), B(4),
  163. AC(3), ABC(2,1), ABC(1,2), BC(3),
  164. /* 5 arguments */
  165. A(5), AB(4,1), AB(3,2), AB(2,3), AB(1,4), B(5),
  166. AC(4), ABC(3,1), ABC(2,2), ABC(1,3), BC(4),
  167. /* 6 arguments */
  168. A(6), AB(5,1), AB(4,2), AB(3,3), AB(2,4), AB(1,5), B(6),
  169. AC(5), ABC(4,1), ABC(3,2), ABC(2,3), ABC(1,4), BC(5),
  170. /* 7 arguments */
  171. A(7), AB(6,1), AB(5,2), AB(4,3), AB(3,4), AB(2,5), AB(1,6), B(7),
  172. AC(6), ABC(5,1), ABC(4,2), ABC(3,3), ABC(2,4), ABC(1,5), BC(6),
  173. /* 8 arguments */
  174. A(8), AB(7,1), AB(6,2), AB(5,3), AB(4,4), AB(3,5), AB(2,6), AB(1,7), B(8),
  175. AC(7), ABC(6,1), ABC(5,2), ABC(4,3), ABC(3,4), ABC(2,5), ABC(1,6), BC(7),
  176. /* 9 arguments */
  177. A(9), AB(8,1), AB(7,2), AB(6,3), AB(5,4), AB(4,5), AB(3,6), AB(2,7), AB(1,8), B(9),
  178. AC(8), ABC(7,1), ABC(6,2), ABC(5,3), ABC(4,4), ABC(3,5), ABC(2,6), ABC(1,7), BC(8),
  179. /* 10 arguments */
  180. A(10), AB(9,1), AB(8,2), AB(7,3), AB(6,4), AB(5,5), AB(4,6), AB(3,7), AB(2,8), AB(1,9), B(10),
  181. AC(9), ABC(8,1), ABC(7,2), ABC(6,3), ABC(5,4), ABC(4,5), ABC(3,6), ABC(2,7), ABC(1,8), BC(9),
  182. };
  183. #undef A
  184. #undef B
  185. #undef C
  186. #undef AB
  187. #undef AC
  188. #undef BC
  189. #undef ABC
  190. /* (nargs * nargs) + nopt + rest * (nargs + 1) */
  191. #define SUBR_STUB_CODE(nreq,nopt,rest) \
  192. &subr_stub_code[((nreq + nopt + rest) * (nreq + nopt + rest) \
  193. + nopt + rest * (nreq + nopt + rest + 1)) * 6]
  194. static const scm_t_uint32*
  195. get_subr_stub_code (unsigned int nreq, unsigned int nopt, unsigned int rest)
  196. {
  197. if (SCM_UNLIKELY (rest > 1 || nreq + nopt + rest > 10))
  198. scm_out_of_range ("make-subr", scm_from_uint (nreq + nopt + rest));
  199. return SUBR_STUB_CODE (nreq, nopt, rest);
  200. }
  201. static SCM
  202. create_subr (int define, const char *name,
  203. unsigned int nreq, unsigned int nopt, unsigned int rest,
  204. SCM (*fcn) (), SCM *generic_loc)
  205. {
  206. SCM ret, sname;
  207. scm_t_bits flags;
  208. scm_t_bits nfree = generic_loc ? 3 : 2;
  209. sname = scm_from_utf8_symbol (name);
  210. flags = SCM_F_PROGRAM_IS_PRIMITIVE;
  211. flags |= generic_loc ? SCM_F_PROGRAM_IS_PRIMITIVE_GENERIC : 0;
  212. ret = scm_words (scm_tc7_program | (nfree << 16) | flags, nfree + 2);
  213. SCM_SET_CELL_WORD_1 (ret, get_subr_stub_code (nreq, nopt, rest));
  214. SCM_PROGRAM_FREE_VARIABLE_SET (ret, 0, scm_from_pointer (fcn, NULL));
  215. SCM_PROGRAM_FREE_VARIABLE_SET (ret, 1, sname);
  216. if (generic_loc)
  217. SCM_PROGRAM_FREE_VARIABLE_SET (ret, 2,
  218. scm_from_pointer (generic_loc, NULL));
  219. if (define)
  220. scm_define (sname, ret);
  221. return ret;
  222. }
  223. int
  224. scm_i_primitive_code_p (const scm_t_uint32 *code)
  225. {
  226. if (code < subr_stub_code)
  227. return 0;
  228. if (code > subr_stub_code + (sizeof(subr_stub_code) / sizeof(scm_t_uint32)))
  229. return 0;
  230. return 1;
  231. }
  232. scm_t_uintptr
  233. scm_i_primitive_call_ip (SCM subr)
  234. {
  235. size_t i;
  236. const scm_t_uint32 *code = SCM_PROGRAM_CODE (subr);
  237. /* A stub is 6 32-bit words long, or 24 bytes. The call will be one
  238. instruction, in either the fourth, third, or second word. Return a
  239. byte offset from the entry. */
  240. for (i = 1; i < 4; i++)
  241. if ((code[i] & 0xff) == scm_op_subr_call)
  242. return (scm_t_uintptr) (code + i);
  243. abort ();
  244. }
  245. SCM
  246. scm_apply_subr (union scm_vm_stack_element *sp, scm_t_ptrdiff nslots)
  247. {
  248. SCM (*subr)() = SCM_SUBRF (sp[nslots - 1].as_scm);
  249. #define ARG(i) (sp[i].as_scm)
  250. switch (nslots - 1)
  251. {
  252. case 0:
  253. return subr ();
  254. case 1:
  255. return subr (ARG (0));
  256. case 2:
  257. return subr (ARG (1), ARG (0));
  258. case 3:
  259. return subr (ARG (2), ARG (1), ARG (0));
  260. case 4:
  261. return subr (ARG (3), ARG (2), ARG (1), ARG (0));
  262. case 5:
  263. return subr (ARG (4), ARG (3), ARG (2), ARG (1), ARG (0));
  264. case 6:
  265. return subr (ARG (5), ARG (4), ARG (3), ARG (2), ARG (1),
  266. ARG (0));
  267. case 7:
  268. return subr (ARG (6), ARG (5), ARG (4), ARG (3), ARG (2),
  269. ARG (1), ARG (0));
  270. case 8:
  271. return subr (ARG (7), ARG (6), ARG (5), ARG (4), ARG (3),
  272. ARG (2), ARG (1), ARG (0));
  273. case 9:
  274. return subr (ARG (8), ARG (7), ARG (6), ARG (5), ARG (4),
  275. ARG (3), ARG (2), ARG (1), ARG (0));
  276. case 10:
  277. return subr (ARG (9), ARG (8), ARG (7), ARG (6), ARG (5),
  278. ARG (4), ARG (3), ARG (2), ARG (1), ARG (0));
  279. default:
  280. abort ();
  281. }
  282. #undef ARG
  283. }
  284. SCM
  285. scm_c_make_gsubr (const char *name, int req, int opt, int rst, SCM (*fcn)())
  286. {
  287. return create_subr (0, name, req, opt, rst, fcn, NULL);
  288. }
  289. SCM
  290. scm_c_define_gsubr (const char *name, int req, int opt, int rst, SCM (*fcn)())
  291. {
  292. return create_subr (1, name, req, opt, rst, fcn, NULL);
  293. }
  294. SCM
  295. scm_c_make_gsubr_with_generic (const char *name,
  296. int req,
  297. int opt,
  298. int rst,
  299. SCM (*fcn)(),
  300. SCM *gf)
  301. {
  302. return create_subr (0, name, req, opt, rst, fcn, gf);
  303. }
  304. SCM
  305. scm_c_define_gsubr_with_generic (const char *name,
  306. int req,
  307. int opt,
  308. int rst,
  309. SCM (*fcn)(),
  310. SCM *gf)
  311. {
  312. return create_subr (1, name, req, opt, rst, fcn, gf);
  313. }
  314. void
  315. scm_init_gsubr()
  316. {
  317. #include "libguile/gsubr.x"
  318. }
  319. /*
  320. Local Variables:
  321. c-file-style: "gnu"
  322. End:
  323. */