Smob-related creanup.
[bpt/guile.git] / libguile / throw.c
CommitLineData
f2c9fcb0 1/* Copyright (C) 1995, 1996, 1997, 1998, 2000 Free Software Foundation, Inc.
0f2d19dd
JB
2 *
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2, or (at your option)
6 * any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this software; see the file COPYING. If not, write to
82892bed
JB
15 * the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
16 * Boston, MA 02111-1307 USA
0f2d19dd
JB
17 *
18 * As a special exception, the Free Software Foundation gives permission
19 * for additional uses of the text contained in its release of GUILE.
20 *
21 * The exception is that, if you link the GUILE library with other files
22 * to produce an executable, this does not by itself cause the
23 * resulting executable to be covered by the GNU General Public License.
24 * Your use of that executable is in no way restricted on account of
25 * linking the GUILE library code into it.
26 *
27 * This exception does not however invalidate any other reasons why
28 * the executable file might be covered by the GNU General Public License.
29 *
30 * This exception applies only to the code released by the
31 * Free Software Foundation under the name GUILE. If you copy
32 * code from other Free Software Foundation releases into a copy of
33 * GUILE, as the General Public License permits, the exception does
34 * not apply to the code that you add in this way. To avoid misleading
35 * anyone as to the status of such modified files, you must delete
36 * this exception notice from them.
37 *
38 * If you write modifications of your own for GUILE, it is your choice
39 * whether to permit this exception to apply to your modifications.
82892bed 40 * If you do not wish that, delete this exception notice. */
1bbd0b84
GB
41
42/* Software engineering face-lift by Greg J. Badros, 11-Dec-1999,
43 gjb@cs.washington.edu, http://www.cs.washington.edu/homes/gjb */
44
0f2d19dd
JB
45\f
46
47#include <stdio.h>
a0599745
MD
48#include "libguile/_scm.h"
49#include "libguile/smob.h"
50#include "libguile/alist.h"
51#include "libguile/eval.h"
52#include "libguile/eq.h"
53#include "libguile/dynwind.h"
54#include "libguile/backtrace.h"
20e6290e 55#ifdef DEBUG_EXTENSIONS
a0599745 56#include "libguile/debug.h"
20e6290e 57#endif
a0599745
MD
58#include "libguile/continuations.h"
59#include "libguile/stackchk.h"
60#include "libguile/stacks.h"
61#include "libguile/fluids.h"
62#include "libguile/ports.h"
0f2d19dd 63
a0599745
MD
64#include "libguile/validate.h"
65#include "libguile/throw.h"
0f2d19dd 66
32f7b3a1 67\f
74229f75 68/* the jump buffer data structure */
e841c3e0 69static scm_bits_t tc16_jmpbuffer;
0f2d19dd 70
e841c3e0 71#define SCM_JMPBUFP(OBJ) SCM_TYP16_PREDICATE (tc16_jmpbuffer, OBJ)
c209c88e 72
e841c3e0
KN
73#define JBACTIVE(OBJ) (SCM_CELL_WORD_0 (OBJ) & (1L << 16L))
74#define ACTIVATEJB(OBJ) (SCM_SETOR_CAR (OBJ, (1L << 16L)))
75#define DEACTIVATEJB(OBJ) (SCM_SETAND_CAR (OBJ, ~(1L << 16L)))
0f2d19dd 76
4260a7fc
DH
77#define JBJMPBUF(OBJ) ((jmp_buf *) SCM_CELL_WORD_1 (OBJ))
78#define SETJBJMPBUF(x,v) (SCM_SET_CELL_WORD_1 ((x), (v)))
1a548472
DH
79#ifdef DEBUG_EXTENSIONS
80#define SCM_JBDFRAME(x) ((scm_debug_frame *) SCM_CELL_WORD_2 (x))
81#define SCM_SETJBDFRAME(x,v) (SCM_SET_CELL_WORD_2 ((x), (v)))
0f2d19dd
JB
82#endif
83
0f2d19dd 84static int
e841c3e0 85jmpbuffer_print (SCM exp, SCM port, scm_print_state *pstate)
0f2d19dd 86{
b7f3516f
TT
87 scm_puts ("#<jmpbuffer ", port);
88 scm_puts (JBACTIVE(exp) ? "(active) " : "(inactive) ", port);
4260a7fc 89 scm_intprint((long) JBJMPBUF (exp), 16, port);
b7f3516f 90 scm_putc ('>', port);
0f2d19dd
JB
91 return 1 ;
92}
93
0f2d19dd 94static SCM
1bbd0b84 95make_jmpbuf (void)
0f2d19dd
JB
96{
97 SCM answer;
7f759d79 98 SCM_REDEFER_INTS;
0f2d19dd 99 {
e137c6b3 100#ifdef DEBUG_EXTENSIONS
e841c3e0 101 SCM_NEWSMOB2 (answer, tc16_jmpbuffer, 0, 0);
23a62151 102#else
e841c3e0 103 SCM_NEWSMOB (answer, tc16_jmpbuffer, 0);
23a62151 104#endif
11702758
MD
105 SETJBJMPBUF(answer, (jmp_buf *)0);
106 DEACTIVATEJB(answer);
0f2d19dd 107 }
7f759d79 108 SCM_REALLOW_INTS;
0f2d19dd
JB
109 return answer;
110}
111
74229f75 112\f
18eadcbe 113/* scm_internal_catch (the guts of catch) */
74229f75 114
0f2d19dd
JB
115struct jmp_buf_and_retval /* use only on the stack, in scm_catch */
116{
117 jmp_buf buf; /* must be first */
118 SCM throw_tag;
119 SCM retval;
120};
121
650fa1ab
JB
122
123/* scm_internal_catch is the guts of catch. It handles all the
124 mechanics of setting up a catch target, invoking the catch body,
125 and perhaps invoking the handler if the body does a throw.
126
127 The function is designed to be usable from C code, but is general
128 enough to implement all the semantics Guile Scheme expects from
129 throw.
130
131 TAG is the catch tag. Typically, this is a symbol, but this
132 function doesn't actually care about that.
133
134 BODY is a pointer to a C function which runs the body of the catch;
135 this is the code you can throw from. We call it like this:
19b27fa2 136 BODY (BODY_DATA)
650fa1ab 137 where:
816a6f06
JB
138 BODY_DATA is just the BODY_DATA argument we received; we pass it
139 through to BODY as its first argument. The caller can make
140 BODY_DATA point to anything useful that BODY might need.
650fa1ab
JB
141
142 HANDLER is a pointer to a C function to deal with a throw to TAG,
143 should one occur. We call it like this:
86327304 144 HANDLER (HANDLER_DATA, THROWN_TAG, THROW_ARGS)
650fa1ab 145 where
816a6f06
JB
146 HANDLER_DATA is the HANDLER_DATA argument we recevied; it's the
147 same idea as BODY_DATA above.
86327304
JB
148 THROWN_TAG is the tag that the user threw to; usually this is
149 TAG, but it could be something else if TAG was #t (i.e., a
150 catch-all), or the user threw to a jmpbuf.
650fa1ab 151 THROW_ARGS is the list of arguments the user passed to the THROW
4dd8323f 152 function, after the tag.
650fa1ab 153
3eed3475
JB
154 BODY_DATA is just a pointer we pass through to BODY. HANDLER_DATA
155 is just a pointer we pass through to HANDLER. We don't actually
156 use either of those pointers otherwise ourselves. The idea is
157 that, if our caller wants to communicate something to BODY or
158 HANDLER, it can pass a pointer to it as MUMBLE_DATA, which BODY and
159 HANDLER can then use. Think of it as a way to make BODY and
160 HANDLER closures, not just functions; MUMBLE_DATA points to the
161 enclosed variables.
162
163 Of course, it's up to the caller to make sure that any data a
164 MUMBLE_DATA needs is protected from GC. A common way to do this is
165 to make MUMBLE_DATA a pointer to data stored in an automatic
166 structure variable; since the collector must scan the stack for
167 references anyway, this assures that any references in MUMBLE_DATA
168 will be found. */
650fa1ab 169
0f2d19dd 170SCM
6e8d25a6 171scm_internal_catch (SCM tag, scm_catch_body_t body, void *body_data, scm_catch_handler_t handler, void *handler_data)
0f2d19dd
JB
172{
173 struct jmp_buf_and_retval jbr;
174 SCM jmpbuf;
175 SCM answer;
176
11702758 177 jmpbuf = make_jmpbuf ();
0f2d19dd
JB
178 answer = SCM_EOL;
179 scm_dynwinds = scm_acons (tag, jmpbuf, scm_dynwinds);
180 SETJBJMPBUF(jmpbuf, &jbr.buf);
181#ifdef DEBUG_EXTENSIONS
e68b42c1 182 SCM_SETJBDFRAME(jmpbuf, scm_last_debug_frame);
0f2d19dd
JB
183#endif
184 if (setjmp (jbr.buf))
185 {
186 SCM throw_tag;
187 SCM throw_args;
188
7f759d79
MD
189#ifdef STACK_CHECKING
190 scm_stack_checking_enabled_p = SCM_STACK_CHECKING_P;
191#endif
192 SCM_REDEFER_INTS;
0f2d19dd
JB
193 DEACTIVATEJB (jmpbuf);
194 scm_dynwinds = SCM_CDR (scm_dynwinds);
7f759d79 195 SCM_REALLOW_INTS;
0f2d19dd
JB
196 throw_args = jbr.retval;
197 throw_tag = jbr.throw_tag;
198 jbr.throw_tag = SCM_EOL;
199 jbr.retval = SCM_EOL;
816a6f06 200 answer = handler (handler_data, throw_tag, throw_args);
0f2d19dd
JB
201 }
202 else
203 {
204 ACTIVATEJB (jmpbuf);
492960a4 205 answer = body (body_data);
7f759d79 206 SCM_REDEFER_INTS;
0f2d19dd
JB
207 DEACTIVATEJB (jmpbuf);
208 scm_dynwinds = SCM_CDR (scm_dynwinds);
7f759d79 209 SCM_REALLOW_INTS;
0f2d19dd
JB
210 }
211 return answer;
212}
213
650fa1ab 214
18eadcbe
JB
215\f
216/* scm_internal_lazy_catch (the guts of lazy catching) */
217
218/* The smob tag for lazy_catch smobs. */
e841c3e0 219static scm_bits_t tc16_lazy_catch;
18eadcbe
JB
220
221/* This is the structure we put on the wind list for a lazy catch. It
222 stores the handler function to call, and the data pointer to pass
223 through to it. It's not a Scheme closure, but it is a function
224 with data, so the term "closure" is appropriate in its broader
225 sense.
226
227 (We don't need anything like this in the "eager" catch code,
228 because the same C frame runs both the body and the handler.) */
229struct lazy_catch {
230 scm_catch_handler_t handler;
231 void *handler_data;
232};
233
234/* Strictly speaking, we could just pass a zero for our print
235 function, because we don't need to print them. They should never
236 appear in normal data structures, only in the wind list. However,
237 it might be nice for debugging someday... */
238static int
e841c3e0 239lazy_catch_print (SCM closure, SCM port, scm_print_state *pstate)
18eadcbe 240{
4260a7fc 241 struct lazy_catch *c = (struct lazy_catch *) SCM_CELL_WORD_1 (closure);
18eadcbe
JB
242 char buf[200];
243
244 sprintf (buf, "#<lazy-catch 0x%lx 0x%lx>",
245 (long) c->handler, (long) c->handler_data);
b7f3516f 246 scm_puts (buf, port);
18eadcbe
JB
247
248 return 1;
249}
250
18eadcbe
JB
251
252/* Given a pointer to a lazy catch structure, return a smob for it,
253