gsubr.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393
  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. 0, \
  64. 0
  65. #define B(nopt) \
  66. SCM_PACK_OP_24 (assert_nargs_le, nopt + 1), \
  67. SCM_PACK_OP_24 (alloc_frame, nopt + 1), \
  68. SCM_PACK_OP_24 (subr_call, 0), \
  69. 0
  70. #define C() \
  71. SCM_PACK_OP_24 (bind_rest, 1), \
  72. SCM_PACK_OP_24 (subr_call, 0), \
  73. 0, \
  74. 0
  75. #define AB(nreq, nopt) \
  76. SCM_PACK_OP_24 (assert_nargs_ge, nreq + 1), \
  77. SCM_PACK_OP_24 (assert_nargs_le, nreq + nopt + 1), \
  78. SCM_PACK_OP_24 (alloc_frame, nreq + nopt + 1), \
  79. SCM_PACK_OP_24 (subr_call, 0)
  80. #define AC(nreq) \
  81. SCM_PACK_OP_24 (assert_nargs_ge, nreq + 1), \
  82. SCM_PACK_OP_24 (bind_rest, nreq + 1), \
  83. SCM_PACK_OP_24 (subr_call, 0), \
  84. 0
  85. #define BC(nopt) \
  86. SCM_PACK_OP_24 (bind_rest, nopt + 1), \
  87. SCM_PACK_OP_24 (subr_call, 0), \
  88. 0, \
  89. 0
  90. #define ABC(nreq, nopt) \
  91. SCM_PACK_OP_24 (assert_nargs_ge, nreq + 1), \
  92. SCM_PACK_OP_24 (bind_rest, nreq + nopt + 1), \
  93. SCM_PACK_OP_24 (subr_call, 0), \
  94. 0
  95. /*
  96. (defun generate-bytecode (n)
  97. "Generate bytecode for N arguments"
  98. (interactive "p")
  99. (insert (format "/\* %d arguments *\/\n " n))
  100. (let ((nreq n))
  101. (while (<= 0 nreq)
  102. (let ((nopt (- n nreq)))
  103. (insert
  104. (if (< 0 nreq)
  105. (if (< 0 nopt)
  106. (format " AB(%d,%d)," nreq nopt)
  107. (format " A(%d)," nreq))
  108. (if (< 0 nopt)
  109. (format " B(%d)," nopt)
  110. (format " A(0),"))))
  111. (setq nreq (1- nreq))))
  112. (insert "\n ")
  113. (setq nreq (1- n))
  114. (while (<= 0 nreq)
  115. (let ((nopt (- n nreq 1)))
  116. (insert
  117. (if (< 0 nreq)
  118. (if (< 0 nopt)
  119. (format " ABC(%d,%d)," nreq nopt)
  120. (format " AC(%d)," nreq))
  121. (if (< 0 nopt)
  122. (format " BC(%d)," nopt)
  123. (format " C(),"))))
  124. (setq nreq (1- nreq))))
  125. (insert "\n\n ")))
  126. (defun generate-bytecodes (n)
  127. "Generate bytecodes for up to N arguments"
  128. (interactive "p")
  129. (let ((i 0))
  130. (while (<= i n)
  131. (generate-bytecode i)
  132. (setq i (1+ i)))))
  133. */
  134. static const scm_t_uint32 subr_stub_code[] = {
  135. /* C-u 1 0 M-x generate-bytecodes RET */
  136. /* 0 arguments */
  137. A(0),
  138. /* 1 arguments */
  139. A(1), B(1),
  140. C(),
  141. /* 2 arguments */
  142. A(2), AB(1,1), B(2),
  143. AC(1), BC(1),
  144. /* 3 arguments */
  145. A(3), AB(2,1), AB(1,2), B(3),
  146. AC(2), ABC(1,1), BC(2),
  147. /* 4 arguments */
  148. A(4), AB(3,1), AB(2,2), AB(1,3), B(4),
  149. AC(3), ABC(2,1), ABC(1,2), BC(3),
  150. /* 5 arguments */
  151. A(5), AB(4,1), AB(3,2), AB(2,3), AB(1,4), B(5),
  152. AC(4), ABC(3,1), ABC(2,2), ABC(1,3), BC(4),
  153. /* 6 arguments */
  154. A(6), AB(5,1), AB(4,2), AB(3,3), AB(2,4), AB(1,5), B(6),
  155. AC(5), ABC(4,1), ABC(3,2), ABC(2,3), ABC(1,4), BC(5),
  156. /* 7 arguments */
  157. A(7), AB(6,1), AB(5,2), AB(4,3), AB(3,4), AB(2,5), AB(1,6), B(7),
  158. AC(6), ABC(5,1), ABC(4,2), ABC(3,3), ABC(2,4), ABC(1,5), BC(6),
  159. /* 8 arguments */
  160. 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),
  161. AC(7), ABC(6,1), ABC(5,2), ABC(4,3), ABC(3,4), ABC(2,5), ABC(1,6), BC(7),
  162. /* 9 arguments */
  163. 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),
  164. 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),
  165. /* 10 arguments */
  166. 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),
  167. 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),
  168. };
  169. #undef A
  170. #undef B
  171. #undef C
  172. #undef AB
  173. #undef AC
  174. #undef BC
  175. #undef ABC
  176. /* (nargs * nargs) + nopt + rest * (nargs + 1) */
  177. #define SUBR_STUB_CODE(nreq,nopt,rest) \
  178. &subr_stub_code[((nreq + nopt + rest) * (nreq + nopt + rest) \
  179. + nopt + rest * (nreq + nopt + rest + 1)) * 4]
  180. static const scm_t_uint32*
  181. get_subr_stub_code (unsigned int nreq, unsigned int nopt, unsigned int rest)
  182. {
  183. if (SCM_UNLIKELY (rest > 1 || nreq + nopt + rest > 10))
  184. scm_out_of_range ("make-subr", scm_from_uint (nreq + nopt + rest));
  185. return SUBR_STUB_CODE (nreq, nopt, rest);
  186. }
  187. static SCM
  188. create_subr (int define, const char *name,
  189. unsigned int nreq, unsigned int nopt, unsigned int rest,
  190. SCM (*fcn) (), SCM *generic_loc)
  191. {
  192. SCM ret, sname;
  193. scm_t_bits flags;
  194. scm_t_bits nfree = generic_loc ? 3 : 2;
  195. sname = scm_from_utf8_symbol (name);
  196. flags = SCM_F_PROGRAM_IS_PRIMITIVE;
  197. flags |= generic_loc ? SCM_F_PROGRAM_IS_PRIMITIVE_GENERIC : 0;
  198. ret = scm_words (scm_tc7_program | (nfree << 16) | flags, nfree + 2);
  199. SCM_SET_CELL_WORD_1 (ret, get_subr_stub_code (nreq, nopt, rest));
  200. SCM_PROGRAM_FREE_VARIABLE_SET (ret, 0, scm_from_pointer (fcn, NULL));
  201. SCM_PROGRAM_FREE_VARIABLE_SET (ret, 1, sname);
  202. if (generic_loc)
  203. SCM_PROGRAM_FREE_VARIABLE_SET (ret, 2,
  204. scm_from_pointer (generic_loc, NULL));
  205. if (define)
  206. scm_define (sname, ret);
  207. return ret;
  208. }
  209. int
  210. scm_i_primitive_code_p (const scm_t_uint32 *code)
  211. {
  212. if (code < subr_stub_code)
  213. return 0;
  214. if (code > subr_stub_code + (sizeof(subr_stub_code) / sizeof(scm_t_uint32)))
  215. return 0;
  216. return 1;
  217. }
  218. /* Given a program that is a primitive, determine its minimum arity.
  219. This is possible because each primitive's code is 4 32-bit words
  220. long, and they are laid out contiguously in an ordered pattern. */
  221. int
  222. scm_i_primitive_arity (SCM prim, int *req, int *opt, int *rest)
  223. {
  224. const scm_t_uint32 *code = SCM_PROGRAM_CODE (prim);
  225. unsigned idx, nargs, base, next;
  226. if (!scm_i_primitive_code_p (code))
  227. return 0;
  228. idx = (code - subr_stub_code) / 4;
  229. nargs = -1;
  230. next = 0;
  231. do
  232. {
  233. base = next;
  234. nargs++;
  235. next = (nargs + 1) * (nargs + 1);
  236. }
  237. while (idx >= next);
  238. *rest = (next - idx) < (idx - base);
  239. *req = *rest ? (next - 1) - idx : (base + nargs) - idx;
  240. *opt = *rest ? idx - (next - nargs) : idx - base;
  241. return 1;
  242. }
  243. scm_t_uintptr
  244. scm_i_primitive_call_ip (SCM subr)
  245. {
  246. const scm_t_uint32 *code = SCM_PROGRAM_CODE (subr);
  247. /* A stub is 4 32-bit words long, or 16 bytes. The call will be one
  248. instruction, in either the fourth, third, or second word. Return a
  249. byte offset from the entry. */
  250. return (scm_t_uintptr)(code + (code[3] ? 3 : code[2] ? 2 : 1));
  251. }
  252. SCM
  253. scm_apply_subr (union scm_vm_stack_element *sp, scm_t_ptrdiff nslots)
  254. {
  255. SCM (*subr)() = SCM_SUBRF (sp[nslots - 1].as_scm);
  256. #define ARG(i) (sp[i].as_scm)
  257. switch (nslots - 1)
  258. {
  259. case 0:
  260. return subr ();
  261. case 1:
  262. return subr (ARG (0));
  263. case 2:
  264. return subr (ARG (1), ARG (0));
  265. case 3:
  266. return subr (ARG (2), ARG (1), ARG (0));
  267. case 4:
  268. return subr (ARG (3), ARG (2), ARG (1), ARG (0));
  269. case 5:
  270. return subr (ARG (4), ARG (3), ARG (2), ARG (1), ARG (0));
  271. case 6:
  272. return subr (ARG (5), ARG (4), ARG (3), ARG (2), ARG (1),
  273. ARG (0));
  274. case 7:
  275. return subr (ARG (6), ARG (5), ARG (4), ARG (3), ARG (2),
  276. ARG (1), ARG (0));
  277. case 8:
  278. return subr (ARG (7), ARG (6), ARG (5), ARG (4), ARG (3),
  279. ARG (2), ARG (1), ARG (0));
  280. case 9:
  281. return subr (ARG (8), ARG (7), ARG (6), ARG (5), ARG (4),
  282. ARG (3), ARG (2), ARG (1), ARG (0));
  283. case 10:
  284. return subr (ARG (9), ARG (8), ARG (7), ARG (6), ARG (5),
  285. ARG (4), ARG (3), ARG (2), ARG (1), ARG (0));
  286. default:
  287. abort ();
  288. }
  289. #undef ARG
  290. }
  291. SCM
  292. scm_c_make_gsubr (const char *name, int req, int opt, int rst, SCM (*fcn)())
  293. {
  294. return create_subr (0, name, req, opt, rst, fcn, NULL);
  295. }
  296. SCM
  297. scm_c_define_gsubr (const char *name, int req, int opt, int rst, SCM (*fcn)())
  298. {
  299. return create_subr (1, name, req, opt, rst, fcn, NULL);
  300. }
  301. SCM
  302. scm_c_make_gsubr_with_generic (const char *name,
  303. int req,
  304. int opt,
  305. int rst,
  306. SCM (*fcn)(),
  307. SCM *gf)
  308. {
  309. return create_subr (0, name, req, opt, rst, fcn, gf);
  310. }
  311. SCM
  312. scm_c_define_gsubr_with_generic (const char *name,
  313. int req,
  314. int opt,
  315. int rst,
  316. SCM (*fcn)(),
  317. SCM *gf)
  318. {
  319. return create_subr (1, name, req, opt, rst, fcn, gf);
  320. }
  321. void
  322. scm_init_gsubr()
  323. {
  324. #include "libguile/gsubr.x"
  325. }
  326. /*
  327. Local Variables:
  328. c-file-style: "gnu"
  329. End:
  330. */