Merge remote-tracking branch 'origin/stable-2.0'
[bpt/guile.git] / libguile / smob.c
CommitLineData
01b69e79
LC
1/* Copyright (C) 1995, 1996, 1998, 1999, 2000, 2001, 2003, 2004, 2006,
2 * 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc.
3 *
73be1d9e 4 * This library is free software; you can redistribute it and/or
53befeb7
NJ
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.
0f2d19dd 8 *
53befeb7
NJ
9 * This library is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
73be1d9e
MV
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
0f2d19dd 13 *
73be1d9e
MV
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
53befeb7
NJ
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 * 02110-1301 USA
73be1d9e 18 */
1bbd0b84 19
1bbd0b84 20
0f2d19dd 21\f
dbb605f5 22#ifdef HAVE_CONFIG_H
f9fe039d
RB
23# include <config.h>
24#endif
0f2d19dd
JB
25
26#include <stdio.h>
34cf38c3 27#include <stdlib.h>
e6e2e95a
MD
28#include <errno.h>
29
a0599745 30#include "libguile/_scm.h"
20e6290e 31
4e047c3e 32#include "libguile/async.h"
9511876f 33#include "libguile/goops.h"
75c3ed28
AW
34#include "libguile/instructions.h"
35#include "libguile/objcodes.h"
36#include "libguile/programs.h"
d7ec6b9f 37
a0599745 38#include "libguile/smob.h"
9dd5943c 39
1c44468d 40#include "libguile/bdw-gc.h"
e9d635e5
LC
41#include <gc/gc_mark.h>
42
43
0f2d19dd
JB
44\f
45
46/* scm_smobs scm_numsmob
7a7f7c53 47 * implement a fixed sized array of smob records.
0f2d19dd
JB
48 * Indexes into this table are used when generating type
49 * tags for smobjects (if you know a tag you can get an index and conversely).
50 */
7a7f7c53 51
c891a40e
LC
52#define MAX_SMOB_COUNT SCM_I_MAX_SMOB_TYPE_COUNT
53
c014a02e 54long scm_numsmob;
7a7f7c53 55scm_smob_descriptor scm_smobs[MAX_SMOB_COUNT];
0f2d19dd 56
197b0573
MV
57void
58scm_assert_smob_type (scm_t_bits tag, SCM val)
59{
60 if (!SCM_SMOB_PREDICATE (tag, val))
61 scm_wrong_type_arg_msg (NULL, 0, val, scm_smobs[SCM_TC2SMOBNUM(tag)].name);
62}
63
9dd5943c
MD
64/* {Mark}
65 */
66
67/* This function is vestigial. It used to be the mark function's
68 responsibility to set the mark bit on the smob or port, but now the
69 generic marking routine in gc.c takes care of that, and a zero
70 pointer for a mark function means "don't bother". So you never
71 need scm_mark0.
72
73 However, we leave it here because it's harmless to call it, and
74 people out there have smob code that uses it, and there's no reason
75 to make their links fail. */
76
77SCM
e81d98ec 78scm_mark0 (SCM ptr SCM_UNUSED)
9dd5943c
MD
79{
80 return SCM_BOOL_F;
81}
82
83SCM
22a52da1
DH
84/* Dirk::FIXME: The name markcdr is misleading, since the term cdr should only
85 be used for real pairs. */
6e8d25a6 86scm_markcdr (SCM ptr)
9dd5943c 87{
22a52da1 88 return SCM_CELL_OBJECT_1 (ptr);
9dd5943c
MD
89}
90
3051344b 91\f
9dd5943c
MD
92/* {Free}
93 */
94
1be6b49c 95size_t
e81d98ec 96scm_free0 (SCM ptr SCM_UNUSED)
9dd5943c
MD
97{
98 return 0;
99}
100
3051344b 101\f
9dd5943c
MD
102/* {Print}
103 */
104
105int
e81d98ec 106scm_smob_print (SCM exp, SCM port, scm_print_state *pstate SCM_UNUSED)
9dd5943c 107{
c014a02e 108 long n = SCM_SMOBNUM (exp);
0607ebbf
AW
109 scm_puts_unlocked ("#<", port);
110 scm_puts_unlocked (SCM_SMOBNAME (n) ? SCM_SMOBNAME (n) : "smob", port);
111 scm_putc_unlocked (' ', port);
7a7f7c53 112 if (scm_smobs[n].size)
0345e278 113 scm_uintprint (SCM_CELL_WORD_1 (exp), 16, port);
7a7f7c53 114 else
0345e278 115 scm_uintprint (SCM_UNPACK (exp), 16, port);
0607ebbf 116 scm_putc_unlocked ('>', port);
9dd5943c
MD
117 return 1;
118}
1cc91f1b 119
75c3ed28 120\f
0717dfd8
KN
121/* {Apply}
122 */
123
80be163f 124static SCM scm_smob_trampolines[16];
75c3ed28 125
80be163f
AW
126/* (nargs * nargs) + nopt + rest * (nargs + 1) */
127#define SCM_SMOB_TRAMPOLINE(nreq,nopt,rest) \
128 scm_smob_trampolines[(nreq + nopt + rest) * (nreq + nopt + rest) \
129 + nopt + rest * (nreq + nopt + rest + 1)]
130
131static SCM
132apply_0 (SCM smob)
75c3ed28 133{
80be163f
AW
134 SCM (*subr)() = SCM_SMOB_DESCRIPTOR (smob).apply;
135 return subr (smob);
136}
137
138static SCM
139apply_1 (SCM smob, SCM a)
75c3ed28 140{
80be163f
AW
141 SCM (*subr)() = SCM_SMOB_DESCRIPTOR (smob).apply;
142 return subr (smob, a);
143}
75c3ed28 144
80be163f
AW
145static SCM
146apply_2 (SCM smob, SCM a, SCM b)
147{
148 SCM (*subr)() = SCM_SMOB_DESCRIPTOR (smob).apply;
149 return subr (smob, a, b);
150}
cb1c46c5
KN
151
152static SCM
80be163f 153apply_3 (SCM smob, SCM a, SCM b, SCM c)
cb1c46c5 154{
80be163f
AW
155 SCM (*subr)() = SCM_SMOB_DESCRIPTOR (smob).apply;
156 return subr (smob, a, b, c);
157}
158
159static SCM
160scm_smob_trampoline (unsigned int nreq, unsigned int nopt,
161 unsigned int rest)
162{
163 SCM trampoline;
164
75c3ed28
AW
165 if (SCM_UNLIKELY (rest > 1 || nreq + nopt + rest > 3))
166 scm_out_of_range ("make-smob", scm_from_uint (nreq + nopt + rest));
167
80be163f
AW
168 trampoline = SCM_SMOB_TRAMPOLINE (nreq, nopt, rest);
169
170 if (SCM_LIKELY (SCM_UNPACK (trampoline)))
171 return trampoline;
172
173 switch (nreq + nopt + rest)
174 {
175 /* The + 1 is for the smob itself. */
176 case 0:
177 trampoline = scm_c_make_gsubr ("apply-smob/0", nreq + 1, nopt, rest,
178 apply_0);
179 break;
180 case 1:
181 trampoline = scm_c_make_gsubr ("apply-smob/1", nreq + 1, nopt, rest,
182 apply_1);
183 break;
184 case 2:
185 trampoline = scm_c_make_gsubr ("apply-smob/2", nreq + 1, nopt, rest,
186 apply_2);
187 break;
188 case 3:
189 trampoline = scm_c_make_gsubr ("apply-smob/3", nreq + 1, nopt, rest,
190 apply_3);
191 break;
192 default:
193 abort ();
194 }
195
196 SCM_SMOB_TRAMPOLINE (nreq, nopt, rest) = trampoline;
197
198 return trampoline;
cb1c46c5
KN
199}
200
201\f
7a7f7c53 202
92c2555f 203scm_t_bits
da0e6c2b 204scm_make_smob_type (char const *name, size_t size)
7a7f7c53 205#define FUNC_NAME "scm_make_smob_type"
0f2d19dd 206{
c014a02e 207 long new_smob;
7a7f7c53 208
9de87eea 209 SCM_CRITICAL_SECTION_START;
7a7f7c53
DH
210 new_smob = scm_numsmob;
211 if (scm_numsmob != MAX_SMOB_COUNT)
212 ++scm_numsmob;
9de87eea 213 SCM_CRITICAL_SECTION_END;
7a7f7c53
DH
214
215 if (new_smob == MAX_SMOB_COUNT)
216 scm_misc_error (FUNC_NAME, "maximum number of smobs exceeded", SCM_EOL);
217
218 scm_smobs[new_smob].name = name;
3051344b 219 scm_smobs[new_smob].size = size;
7a7f7c53 220
d7ec6b9f 221 /* Make a class object if Goops is present. */
47455469 222 if (SCM_UNPACK (scm_smob_class[0]) != 0)
74b6d6e4 223 scm_smob_class[new_smob] = scm_make_extended_class (name, 0);
7a7f7c53
DH
224
225 return scm_tc7_smob + new_smob * 256;
0f2d19dd 226}
7a7f7c53
DH
227#undef FUNC_NAME
228
0f2d19dd 229
9dd5943c 230void
92c2555f 231scm_set_smob_mark (scm_t_bits tc, SCM (*mark) (SCM))
9dd5943c
MD
232{
233 scm_smobs[SCM_TC2SMOBNUM (tc)].mark = mark;
234}
235
236void
92c2555f 237scm_set_smob_free (scm_t_bits tc, size_t (*free) (SCM))
9dd5943c
MD
238{
239 scm_smobs[SCM_TC2SMOBNUM (tc)].free = free;
240}
241
242void
92c2555f 243scm_set_smob_print (scm_t_bits tc, int (*print) (SCM, SCM, scm_print_state*))
9dd5943c
MD
244{
245 scm_smobs[SCM_TC2SMOBNUM (tc)].print = print;
246}
247
248void
92c2555f 249scm_set_smob_equalp (scm_t_bits tc, SCM (*equalp) (SCM, SCM))
9dd5943c
MD
250{
251 scm_smobs[SCM_TC2SMOBNUM (tc)].equalp = equalp;
252}
253
0717dfd8 254void
92c2555f 255scm_set_smob_apply (scm_t_bits tc, SCM (*apply) (),
7c58e21b 256 unsigned int req, unsigned int opt, unsigned int rst)
0717dfd8 257{
80be163f
AW
258 SCM trampoline = scm_smob_trampoline (req, opt, rst);
259
260 scm_smobs[SCM_TC2SMOBNUM (tc)].apply = apply;
261 scm_smobs[SCM_TC2SMOBNUM (tc)].apply_trampoline = trampoline;
cb1c46c5 262
75c3ed28
AW
263 if (SCM_UNPACK (scm_smob_class[0]) != 0)
264 scm_i_inherit_applicable (scm_smob_class[SCM_TC2SMOBNUM (tc)]);
265}
cb1c46c5 266
9dd5943c 267SCM
92c2555f 268scm_make_smob (scm_t_bits tc)
9dd5943c 269{
4a6a4b49 270 scm_t_bits n = SCM_TC2SMOBNUM (tc);
1be6b49c 271 size_t size = scm_smobs[n].size;
16d4699b 272 scm_t_bits data = (size > 0
4c9419ac 273 ? (scm_t_bits) scm_gc_malloc (size, SCM_SMOBNAME (n))
16d4699b 274 : 0);
4a6a4b49
LC
275
276 SCM_RETURN_NEWSMOB (tc, data);
9dd5943c
MD
277}
278
ceef3208 279
378f2625
LC
280\f
281/* Marking SMOBs using user-supplied mark procedures. */
282
378f2625 283
1f7de769
LC
284/* The GC kind used for SMOB types that provide a custom mark procedure. */
285static int smob_gc_kind;
378f2625 286
01b69e79
LC
287/* Mark stack pointer and limit, used by `scm_gc_mark'. */
288static scm_i_pthread_key_t current_mark_stack_pointer;
289static scm_i_pthread_key_t current_mark_stack_limit;
290
378f2625 291
27583e74
AW
292/* The generic SMOB mark procedure that gets called for SMOBs allocated
293 with smob_gc_kind. */
378f2625
LC
294static struct GC_ms_entry *
295smob_mark (GC_word *addr, struct GC_ms_entry *mark_stack_ptr,
296 struct GC_ms_entry *mark_stack_limit, GC_word env)
297{
298 register SCM cell;
194c0a3e
LC
299 register scm_t_bits tc, smobnum;
300
21041372 301 cell = SCM_PACK_POINTER (addr);
194c0a3e
LC
302
303 if (SCM_TYP7 (cell) != scm_tc7_smob)
304 /* It is likely that the GC passed us a pointer to a free-list element
305 which we must ignore (see warning in `gc/gc_mark.h'). */
306 return mark_stack_ptr;
378f2625 307
378f2625
LC
308 tc = SCM_CELL_WORD_0 (cell);
309 smobnum = SCM_TC2SMOBNUM (tc);
310
311 if (smobnum >= scm_numsmob)
194c0a3e 312 /* The first word looks corrupt. */
378f2625
LC
313 abort ();
314
378f2625
LC
315 mark_stack_ptr = GC_MARK_AND_PUSH (SCM2PTR (SCM_CELL_OBJECT_1 (cell)),
316 mark_stack_ptr,
317 mark_stack_limit, NULL);
318 mark_stack_ptr = GC_MARK_AND_PUSH (SCM2PTR (SCM_CELL_OBJECT_2 (cell)),
319 mark_stack_ptr,
320 mark_stack_limit, NULL);
321 mark_stack_ptr = GC_MARK_AND_PUSH (SCM2PTR (SCM_CELL_OBJECT_3 (cell)),
322 mark_stack_ptr,
323 mark_stack_limit, NULL);
324
325 if (scm_smobs[smobnum].mark)
326 {
327 SCM obj;
328
01b69e79
LC
329 scm_i_pthread_setspecific (current_mark_stack_pointer, mark_stack_ptr);
330 scm_i_pthread_setspecific (current_mark_stack_limit, mark_stack_limit);
378f2625
LC
331
332 /* Invoke the SMOB's mark procedure, which will in turn invoke
01b69e79 333 `scm_gc_mark', which may modify `current_mark_stack_pointer'. */
378f2625
LC
334 obj = scm_smobs[smobnum].mark (cell);
335
01b69e79 336 mark_stack_ptr = scm_i_pthread_getspecific (current_mark_stack_pointer);
378f2625 337
8c5bb729 338 if (SCM_HEAP_OBJECT_P (obj))
378f2625
LC
339 /* Mark the returned object. */
340 mark_stack_ptr = GC_MARK_AND_PUSH (SCM2PTR (obj),
341 mark_stack_ptr,
342 mark_stack_limit, NULL);
343
01b69e79
LC
344 scm_i_pthread_setspecific (current_mark_stack_pointer, NULL);
345 scm_i_pthread_setspecific (current_mark_stack_limit, NULL);
378f2625
LC
346 }
347
348 return mark_stack_ptr;
349
350}
351
01b69e79
LC
352/* Mark object O. We assume that this function is only called during the mark
353 phase, i.e., from within `smob_mark' or one of its descendants. */
378f2625
LC
354void
355scm_gc_mark (SCM o)
356{
8c5bb729 357 if (SCM_HEAP_OBJECT_P (o))
378f2625 358 {
01b69e79 359 void *mark_stack_ptr, *mark_stack_limit;
378f2625 360
01b69e79
LC
361 mark_stack_ptr = scm_i_pthread_getspecific (current_mark_stack_pointer);
362 mark_stack_limit = scm_i_pthread_getspecific (current_mark_stack_limit);
363
364 if (mark_stack_ptr == NULL)
378f2625
LC
365 /* The function was not called from a mark procedure. */
366 abort ();
367
368 mark_stack_ptr = GC_MARK_AND_PUSH (SCM2PTR (o),
01b69e79 369 mark_stack_ptr, mark_stack_limit,
378f2625 370 NULL);
01b69e79 371 scm_i_pthread_setspecific (current_mark_stack_pointer, mark_stack_ptr);
378f2625
LC
372 }
373}
374
e9d635e5
LC
375\f
376/* Finalize SMOB by calling its SMOB type's free function, if any. */
27583e74 377static void
6922d92f 378finalize_smob (void *ptr, void *data)
e9d635e5 379{
10fb3386 380 SCM smob;
e9d635e5
LC
381 size_t (* free_smob) (SCM);
382
21041372 383 smob = SCM_PACK_POINTER (ptr);
10fb3386
LC
384#if 0
385 printf ("finalizing SMOB %p (smobnum: %u)\n",
386 ptr, SCM_SMOBNUM (smob));
387#endif
388
e9d635e5
LC
389 free_smob = scm_smobs[SCM_SMOBNUM (smob)].free;
390 if (free_smob)
391 free_smob (smob);
e9d635e5 392}
378f2625 393
27583e74
AW
394/* Return a SMOB with typecode TC. The SMOB type corresponding to TC may
395 provide a custom mark procedure and it will be honored. */
396SCM
397scm_i_new_smob (scm_t_bits tc, scm_t_bits data)
398{
399 scm_t_bits smobnum = SCM_TC2SMOBNUM (tc);
400 SCM ret;
401
402 /* Use the smob_gc_kind if needed to allow the mark procedure to
403 run. Since the marker only deals with double cells, that case
404 allocates a double cell. We leave words 2 and 3 to there initial
405 values, which is 0. */
406 if (scm_smobs [smobnum].mark)
21041372 407 ret = SCM_PACK_POINTER (GC_generic_malloc (2 * sizeof (scm_t_cell), smob_gc_kind));
27583e74 408 else
21041372 409 ret = SCM_PACK_POINTER (GC_MALLOC (sizeof (scm_t_cell)));
27583e74
AW
410
411 SCM_SET_CELL_WORD_1 (ret, data);
412 SCM_SET_CELL_WORD_0 (ret, tc);
413
414 if (scm_smobs[smobnum].free)
6978c673 415 scm_i_set_finalizer (SCM2PTR (ret), finalize_smob, NULL);
27583e74
AW
416
417 return ret;
418}
419
420/* Return a SMOB with typecode TC. The SMOB type corresponding to TC may
421 provide a custom mark procedure and it will be honored. */
422SCM
423scm_i_new_double_smob (scm_t_bits tc, scm_t_bits data1,
424 scm_t_bits data2, scm_t_bits data3)
425{
426 scm_t_bits smobnum = SCM_TC2SMOBNUM (tc);
427 SCM ret;
428
429 /* Use the smob_gc_kind if needed to allow the mark procedure to
430 run. */
431 if (scm_smobs [smobnum].mark)
21041372 432 ret = SCM_PACK_POINTER (GC_generic_malloc (2 * sizeof (scm_t_cell), smob_gc_kind));
27583e74 433 else
21041372 434 ret = SCM_PACK_POINTER (GC_MALLOC (2 * sizeof (scm_t_cell)));
27583e74
AW
435
436 SCM_SET_CELL_WORD_3 (ret, data3);
437 SCM_SET_CELL_WORD_2 (ret, data2);
438 SCM_SET_CELL_WORD_1 (ret, data1);
439 SCM_SET_CELL_WORD_0 (ret, tc);
440
441 if (scm_smobs[smobnum].free)
6978c673 442 scm_i_set_finalizer (SCM2PTR (ret), finalize_smob, NULL);
27583e74
AW
443
444 return ret;
445}
446
378f2625 447\f
0f2d19dd
JB
448void
449scm_smob_prehistory ()
0f2d19dd 450{
c014a02e 451 long i;
e841c3e0 452
01b69e79
LC
453 scm_i_pthread_key_create (&current_mark_stack_pointer, NULL);
454 scm_i_pthread_key_create (&current_mark_stack_limit, NULL);
455
1f7de769 456 smob_gc_kind = GC_new_kind (GC_new_free_list (),
378f2625 457 GC_MAKE_PROC (GC_new_proc (smob_mark), 0),
62779634
LC
458 0,
459 /* Clear new objects. As of version 7.1, libgc
460 doesn't seem to support passing 0 here. */
461 1);
378f2625 462
0f2d19dd 463 scm_numsmob = 0;
7a7f7c53
DH
464 for (i = 0; i < MAX_SMOB_COUNT; ++i)
465 {
466 scm_smobs[i].name = 0;
467 scm_smobs[i].size = 0;
468 scm_smobs[i].mark = 0;
469 scm_smobs[i].free = 0;
470 scm_smobs[i].print = scm_smob_print;
471 scm_smobs[i].equalp = 0;
472 scm_smobs[i].apply = 0;
80be163f 473 scm_smobs[i].apply_trampoline = SCM_BOOL_F;
7a7f7c53 474 }
0f2d19dd 475}
89e00824
ML
476
477/*
478 Local Variables:
479 c-file-style: "gnu"
480 End:
481*/