1 /* Copyright (C) 1995,1996,1997,1998,1999,2000,2001, 2006, 2008, 2009, 2010, 2011, 2013 Free Software Foundation, Inc.
3 * This library is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU Lesser General Public License
5 * as published by the Free Software Foundation; either version 3 of
6 * the License, or (at your option) any later version.
8 * This library is distributed in the hope that it will be useful, but
9 * WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with this library; if not, write to the Free Software
15 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
27 #include "libguile/_scm.h"
28 #include "libguile/gsubr.h"
29 #include "libguile/foreign.h"
30 #include "libguile/instructions.h"
31 #include "libguile/objcodes.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, along with their meta-information, and then wrap them into
47 statically allocated objcode values. Ready? Right!
50 /* There's a maximum of 10 args, so the number of possible combinations is:
52 for 0 args: 1 (000) (1 + 0)
53 for 1 arg: 3 (100, 010, 001) (2 + 1)
54 for 2 args: 5 (200, 110, 020, 101, 011) (3 + 2)
55 for 3 args: 7 (300, 210, 120, 030, 201, 111, 021) (4 + 3)
58 and the index at which N args starts:
67 (1 + 3 + 5 + ... + (2N+1))
68 = ((2N+1)+1)/2 * (N+1)
72 Thus the total sum is 11^2 = 121. Let's just generate all of them as
76 /* A: req; B: opt; C: rest */
78 SCM_PACK_RTL_24 (scm_rtl_op_assert_nargs_ee, nreq + 1), \
79 SCM_PACK_RTL_24 (scm_rtl_op_subr_call, 0), \
84 SCM_PACK_RTL_24 (scm_rtl_op_assert_nargs_le, nopt + 1), \
85 SCM_PACK_RTL_24 (scm_rtl_op_alloc_frame, nopt + 1), \
86 SCM_PACK_RTL_24 (scm_rtl_op_subr_call, 0), \
90 SCM_PACK_RTL_24 (scm_rtl_op_bind_rest, 1), \
91 SCM_PACK_RTL_24 (scm_rtl_op_subr_call, 0), \
95 #define AB(nreq, nopt) \
96 SCM_PACK_RTL_24 (scm_rtl_op_assert_nargs_ge, nreq + 1), \
97 SCM_PACK_RTL_24 (scm_rtl_op_assert_nargs_le, nreq + nopt + 1), \
98 SCM_PACK_RTL_24 (scm_rtl_op_alloc_frame, nreq + nopt + 1), \
99 SCM_PACK_RTL_24 (scm_rtl_op_subr_call, 0)
102 SCM_PACK_RTL_24 (scm_rtl_op_assert_nargs_ge, nreq + 1), \
103 SCM_PACK_RTL_24 (scm_rtl_op_bind_rest, nreq + 1), \
104 SCM_PACK_RTL_24 (scm_rtl_op_subr_call, 0), \
108 SCM_PACK_RTL_24 (scm_rtl_op_bind_rest, nopt + 1), \
109 SCM_PACK_RTL_24 (scm_rtl_op_subr_call, 0), \
113 #define ABC(nreq, nopt) \
114 SCM_PACK_RTL_24 (scm_rtl_op_assert_nargs_ge, nreq + 1), \
115 SCM_PACK_RTL_24 (scm_rtl_op_bind_rest, nreq + nopt + 1), \
116 SCM_PACK_RTL_24 (scm_rtl_op_subr_call, 0), \
121 (defun generate-bytecode (n)
122 "Generate bytecode for N arguments"
124 (insert (format "/\* %d arguments *\/\n " n))
127 (let ((nopt (- n nreq)))
131 (format " AB(%d,%d)," nreq nopt)
132 (format " A(%d)," nreq))
134 (format " B(%d)," nopt)
136 (setq nreq (1- nreq))))
140 (let ((nopt (- n nreq 1)))
144 (format " ABC(%d,%d)," nreq nopt)
145 (format " AC(%d)," nreq))
147 (format " BC(%d)," nopt)
149 (setq nreq (1- nreq))))
152 (defun generate-bytecodes (n)
153 "Generate bytecodes for up to N arguments"
157 (generate-bytecode i)
160 static const scm_t_uint32 subr_stub_code
[] = {
161 /* C-u 1 0 M-x generate-bytecodes RET */
174 A(3), AB(2,1), AB(1,2), B(3),
175 AC(2), ABC(1,1), BC(2),
178 A(4), AB(3,1), AB(2,2), AB(1,3), B(4),
179 AC(3), ABC(2,1), ABC(1,2), BC(3),
182 A(5), AB(4,1), AB(3,2), AB(2,3), AB(1,4), B(5),
183 AC(4), ABC(3,1), ABC(2,2), ABC(1,3), BC(4),
186 A(6), AB(5,1), AB(4,2), AB(3,3), AB(2,4), AB(1,5), B(6),
187 AC(5), ABC(4,1), ABC(3,2), ABC(2,3), ABC(1,4), BC(5),
190 A(7), AB(6,1), AB(5,2), AB(4,3), AB(3,4), AB(2,5), AB(1,6), B(7),
191 AC(6), ABC(5,1), ABC(4,2), ABC(3,3), ABC(2,4), ABC(1,5), BC(6),
194 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),
195 AC(7), ABC(6,1), ABC(5,2), ABC(4,3), ABC(3,4), ABC(2,5), ABC(1,6), BC(7),
198 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),
199 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),
202 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),
203 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),
214 /* (nargs * nargs) + nopt + rest * (nargs + 1) */
215 #define SUBR_STUB_CODE(nreq,nopt,rest) \
216 &subr_stub_code[((nreq + nopt + rest) * (nreq + nopt + rest) \
217 + nopt + rest * (nreq + nopt + rest + 1)) * 4]
219 static const scm_t_uint32
*
220 get_subr_stub_code (unsigned int nreq
, unsigned int nopt
, unsigned int rest
)
222 if (SCM_UNLIKELY (rest
> 1 || nreq
+ nopt
+ rest
> 10))
223 scm_out_of_range ("make-subr", scm_from_uint (nreq
+ nopt
+ rest
));
225 return SUBR_STUB_CODE (nreq
, nopt
, rest
);
229 create_subr (int define
, const char *name
,
230 unsigned int nreq
, unsigned int nopt
, unsigned int rest
,
231 SCM (*fcn
) (), SCM
*generic_loc
)
235 scm_t_bits nfree
= generic_loc
? 3 : 2;
237 sname
= scm_from_utf8_symbol (name
);
239 flags
= SCM_F_PROGRAM_IS_PRIMITIVE
;
240 flags
|= generic_loc
? SCM_F_PROGRAM_IS_PRIMITIVE_GENERIC
: 0;
242 ret
= scm_words (scm_tc7_program
| (nfree
<< 16) | flags
, nfree
+ 2);
243 SCM_SET_CELL_WORD_1 (ret
, get_subr_stub_code (nreq
, nopt
, rest
));
244 SCM_PROGRAM_FREE_VARIABLE_SET (ret
, 0, scm_from_pointer (fcn
, NULL
));
245 SCM_PROGRAM_FREE_VARIABLE_SET (ret
, 1, sname
);
247 SCM_PROGRAM_FREE_VARIABLE_SET (ret
, 2,
248 scm_from_pointer (generic_loc
, NULL
));
251 scm_define (sname
, ret
);
256 /* Given an RTL primitive, determine its minimum arity. This is
257 possible because each RTL primitive is 4 32-bit words long, and they
258 are laid out contiguously in an ordered pattern. */
260 scm_i_primitive_arity (SCM prim
, int *req
, int *opt
, int *rest
)
262 const scm_t_uint32
*code
= SCM_PROGRAM_CODE (prim
);
263 unsigned idx
, nargs
, base
, next
;
265 if (code
< subr_stub_code
)
267 if (code
> subr_stub_code
+ (sizeof(subr_stub_code
) / sizeof(scm_t_uint32
)))
270 idx
= (code
- subr_stub_code
) / 4;
278 next
= (nargs
+ 1) * (nargs
+ 1);
282 *rest
= (next
- idx
) < (idx
- base
);
283 *req
= *rest
? (next
- 1) - idx
: (base
+ nargs
) - idx
;
284 *opt
= *rest
? idx
- (next
- nargs
) : idx
- base
;
290 scm_i_primitive_call_ip (SCM subr
)
292 const scm_t_uint32
*code
= SCM_PROGRAM_CODE (subr
);
294 /* A stub is 4 32-bit words long, or 16 bytes. The call will be one
295 instruction, in either the fourth, third, or second word. Return a
296 byte offset from the entry. */
297 return (scm_t_uintptr
)(code
+ (code
[3] ? 3 : code
[2] ? 2 : 1));
301 scm_c_make_gsubr (const char *name
, int req
, int opt
, int rst
, SCM (*fcn
)())
303 return create_subr (0, name
, req
, opt
, rst
, fcn
, NULL
);
307 scm_c_define_gsubr (const char *name
, int req
, int opt
, int rst
, SCM (*fcn
)())
309 return create_subr (1, name
, req
, opt
, rst
, fcn
, NULL
);
313 scm_c_make_gsubr_with_generic (const char *name
,
320 return create_subr (0, name
, req
, opt
, rst
, fcn
, gf
);
324 scm_c_define_gsubr_with_generic (const char *name
,
331 return create_subr (1, name
, req
, opt
, rst
, fcn
, gf
);
337 #include "libguile/gsubr.x"