1 /* Copyright (C) 1995-2001, 2006, 2008-2011, 2013
2 * Free Software Foundation, Inc.
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.
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.
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
28 #include "libguile/_scm.h"
29 #include "libguile/gsubr.h"
30 #include "libguile/foreign.h"
31 #include "libguile/instructions.h"
32 #include "libguile/srfi-4.h"
33 #include "libguile/programs.h"
35 #include "libguile/private-options.h"
39 * Provide `gsubrs' -- subrs taking a prescribed number of required, optional,
45 /* OK here goes nothing: we're going to define VM assembly trampolines for
46 invoking subrs. Ready? Right! */
48 /* There's a maximum of 10 args, so the number of possible combinations is:
50 for 0 args: 1 (000) (1 + 0)
51 for 1 arg: 3 (100, 010, 001) (2 + 1)
52 for 2 args: 5 (200, 110, 020, 101, 011) (3 + 2)
53 for 3 args: 7 (300, 210, 120, 030, 201, 111, 021) (4 + 3)
56 and the index at which N args starts:
65 (1 + 3 + 5 + ... + (2N+1))
66 = ((2N+1)+1)/2 * (N+1)
70 Thus the total sum is 11^2 = 121. Let's just generate all of them as
74 /* A: req; B: opt; C: rest */
76 SCM_PACK_OP_24 (assert_nargs_ee, nreq + 1), \
77 SCM_PACK_OP_24 (subr_call, 0), \
82 SCM_PACK_OP_24 (assert_nargs_le, nopt + 1), \
83 SCM_PACK_OP_24 (alloc_frame, nopt + 1), \
84 SCM_PACK_OP_24 (subr_call, 0), \
88 SCM_PACK_OP_24 (bind_rest, 1), \
89 SCM_PACK_OP_24 (subr_call, 0), \
93 #define AB(nreq, nopt) \
94 SCM_PACK_OP_24 (assert_nargs_ge, nreq + 1), \
95 SCM_PACK_OP_24 (assert_nargs_le, nreq + nopt + 1), \
96 SCM_PACK_OP_24 (alloc_frame, nreq + nopt + 1), \
97 SCM_PACK_OP_24 (subr_call, 0)
100 SCM_PACK_OP_24 (assert_nargs_ge, nreq + 1), \
101 SCM_PACK_OP_24 (bind_rest, nreq + 1), \
102 SCM_PACK_OP_24 (subr_call, 0), \
106 SCM_PACK_OP_24 (bind_rest, nopt + 1), \
107 SCM_PACK_OP_24 (subr_call, 0), \
111 #define ABC(nreq, nopt) \
112 SCM_PACK_OP_24 (assert_nargs_ge, nreq + 1), \
113 SCM_PACK_OP_24 (bind_rest, nreq + nopt + 1), \
114 SCM_PACK_OP_24 (subr_call, 0), \
119 (defun generate-bytecode (n)
120 "Generate bytecode for N arguments"
122 (insert (format "/\* %d arguments *\/\n " n))
125 (let ((nopt (- n nreq)))
129 (format " AB(%d,%d)," nreq nopt)
130 (format " A(%d)," nreq))
132 (format " B(%d)," nopt)
134 (setq nreq (1- nreq))))
138 (let ((nopt (- n nreq 1)))
142 (format " ABC(%d,%d)," nreq nopt)
143 (format " AC(%d)," nreq))
145 (format " BC(%d)," nopt)
147 (setq nreq (1- nreq))))
150 (defun generate-bytecodes (n)
151 "Generate bytecodes for up to N arguments"
155 (generate-bytecode i)
158 static const scm_t_uint32 subr_stub_code
[] = {
159 /* C-u 1 0 M-x generate-bytecodes RET */
172 A(3), AB(2,1), AB(1,2), B(3),
173 AC(2), ABC(1,1), BC(2),
176 A(4), AB(3,1), AB(2,2), AB(1,3), B(4),
177 AC(3), ABC(2,1), ABC(1,2), BC(3),
180 A(5), AB(4,1), AB(3,2), AB(2,3), AB(1,4), B(5),
181 AC(4), ABC(3,1), ABC(2,2), ABC(1,3), BC(4),
184 A(6), AB(5,1), AB(4,2), AB(3,3), AB(2,4), AB(1,5), B(6),
185 AC(5), ABC(4,1), ABC(3,2), ABC(2,3), ABC(1,4), BC(5),
188 A(7), AB(6,1), AB(5,2), AB(4,3), AB(3,4), AB(2,5), AB(1,6), B(7),
189 AC(6), ABC(5,1), ABC(4,2), ABC(3,3), ABC(2,4), ABC(1,5), BC(6),
192 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),
193 AC(7), ABC(6,1), ABC(5,2), ABC(4,3), ABC(3,4), ABC(2,5), ABC(1,6), BC(7),
196 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),
197 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),
200 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),
201 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),
212 /* (nargs * nargs) + nopt + rest * (nargs + 1) */
213 #define SUBR_STUB_CODE(nreq,nopt,rest) \
214 &subr_stub_code[((nreq + nopt + rest) * (nreq + nopt + rest) \
215 + nopt + rest * (nreq + nopt + rest + 1)) * 4]
217 static const scm_t_uint32
*
218 get_subr_stub_code (unsigned int nreq
, unsigned int nopt
, unsigned int rest
)
220 if (SCM_UNLIKELY (rest
> 1 || nreq
+ nopt
+ rest
> 10))
221 scm_out_of_range ("make-subr", scm_from_uint (nreq
+ nopt
+ rest
));
223 return SUBR_STUB_CODE (nreq
, nopt
, rest
);
227 create_subr (int define
, const char *name
,
228 unsigned int nreq
, unsigned int nopt
, unsigned int rest
,
229 SCM (*fcn
) (), SCM
*generic_loc
)
233 scm_t_bits nfree
= generic_loc
? 3 : 2;
235 sname
= scm_from_utf8_symbol (name
);
237 flags
= SCM_F_PROGRAM_IS_PRIMITIVE
;
238 flags
|= generic_loc
? SCM_F_PROGRAM_IS_PRIMITIVE_GENERIC
: 0;
240 ret
= scm_words (scm_tc7_program
| (nfree
<< 16) | flags
, nfree
+ 2);
241 SCM_SET_CELL_WORD_1 (ret
, get_subr_stub_code (nreq
, nopt
, rest
));
242 SCM_PROGRAM_FREE_VARIABLE_SET (ret
, 0, scm_from_pointer (fcn
, NULL
));
243 SCM_PROGRAM_FREE_VARIABLE_SET (ret
, 1, sname
);
245 SCM_PROGRAM_FREE_VARIABLE_SET (ret
, 2,
246 scm_from_pointer (generic_loc
, NULL
));
249 scm_define (sname
, ret
);
254 /* Given a program that is a primitive, determine its minimum arity.
255 This is possible because each primitive's code is 4 32-bit words
256 long, and they are laid out contiguously in an ordered pattern. */
258 scm_i_primitive_arity (SCM prim
, int *req
, int *opt
, int *rest
)
260 const scm_t_uint32
*code
= SCM_PROGRAM_CODE (prim
);
261 unsigned idx
, nargs
, base
, next
;
263 if (code
< subr_stub_code
)
265 if (code
> subr_stub_code
+ (sizeof(subr_stub_code
) / sizeof(scm_t_uint32
)))
268 idx
= (code
- subr_stub_code
) / 4;
276 next
= (nargs
+ 1) * (nargs
+ 1);
280 *rest
= (next
- idx
) < (idx
- base
);
281 *req
= *rest
? (next
- 1) - idx
: (base
+ nargs
) - idx
;
282 *opt
= *rest
? idx
- (next
- nargs
) : idx
- base
;
288 scm_i_primitive_call_ip (SCM subr
)
290 const scm_t_uint32
*code
= SCM_PROGRAM_CODE (subr
);
292 /* A stub is 4 32-bit words long, or 16 bytes. The call will be one
293 instruction, in either the fourth, third, or second word. Return a
294 byte offset from the entry. */
295 return (scm_t_uintptr
)(code
+ (code
[3] ? 3 : code
[2] ? 2 : 1));
299 scm_c_make_gsubr (const char *name
, int req
, int opt
, int rst
, SCM (*fcn
)())
301 return create_subr (0, name
, req
, opt
, rst
, fcn
, NULL
);
305 scm_c_define_gsubr (const char *name
, int req
, int opt
, int rst
, SCM (*fcn
)())
307 return create_subr (1, name
, req
, opt
, rst
, fcn
, NULL
);
311 scm_c_make_gsubr_with_generic (const char *name
,
318 return create_subr (0, name
, req
, opt
, rst
, fcn
, gf
);
322 scm_c_define_gsubr_with_generic (const char *name
,
329 return create_subr (1, name
, req
, opt
, rst
, fcn
, gf
);
335 #include "libguile/gsubr.x"