Try to optimize scm_string for speed
[bpt/guile.git] / libguile / throw.c
... / ...
CommitLineData
1/* Copyright (C) 1995,1996,1997,1998,2000,2001, 2003, 2004, 2006, 2008 Free Software Foundation, Inc.
2 *
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.
7 *
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.
12 *
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
16 * 02110-1301 USA
17 */
18
19
20\f
21#ifdef HAVE_CONFIG_H
22# include <config.h>
23#endif
24
25#include <stdio.h>
26#include "libguile/_scm.h"
27#include "libguile/async.h"
28#include "libguile/smob.h"
29#include "libguile/alist.h"
30#include "libguile/eval.h"
31#include "libguile/eq.h"
32#include "libguile/dynwind.h"
33#include "libguile/backtrace.h"
34#include "libguile/debug.h"
35#include "libguile/continuations.h"
36#include "libguile/stackchk.h"
37#include "libguile/stacks.h"
38#include "libguile/fluids.h"
39#include "libguile/ports.h"
40#include "libguile/lang.h"
41#include "libguile/validate.h"
42#include "libguile/throw.h"
43#include "libguile/init.h"
44#include "libguile/strings.h"
45#include "libguile/vm.h"
46
47#include "libguile/private-options.h"
48
49
50\f
51/* the jump buffer data structure */
52static scm_t_bits tc16_jmpbuffer;
53
54#define SCM_JMPBUFP(OBJ) SCM_TYP16_PREDICATE (tc16_jmpbuffer, OBJ)
55
56#define JBACTIVE(OBJ) (SCM_CELL_WORD_0 (OBJ) & (1L << 16L))
57#define ACTIVATEJB(x) \
58 (SCM_SET_CELL_WORD_0 ((x), (SCM_CELL_WORD_0 (x) | (1L << 16L))))
59#define DEACTIVATEJB(x) \
60 (SCM_SET_CELL_WORD_0 ((x), (SCM_CELL_WORD_0 (x) & ~(1L << 16L))))
61
62#define JBJMPBUF(OBJ) ((jmp_buf *) SCM_CELL_WORD_1 (OBJ))
63#define SETJBJMPBUF(x, v) (SCM_SET_CELL_WORD_1 ((x), (scm_t_bits) (v)))
64#define SCM_JBDFRAME(x) ((scm_t_debug_frame *) SCM_CELL_WORD_2 (x))
65#define SCM_SETJBDFRAME(x, v) (SCM_SET_CELL_WORD_2 ((x), (scm_t_bits) (v)))
66#define SCM_JBPREUNWIND(x) ((struct pre_unwind_data *) SCM_CELL_WORD_3 (x))
67#define SCM_SETJBPREUNWIND(x, v) (SCM_SET_CELL_WORD_3 ((x), (scm_t_bits) (v)))
68
69static int
70jmpbuffer_print (SCM exp, SCM port, scm_print_state *pstate SCM_UNUSED)
71{
72 scm_puts ("#<jmpbuffer ", port);
73 scm_puts (JBACTIVE(exp) ? "(active) " : "(inactive) ", port);
74 scm_uintprint((scm_t_bits) JBJMPBUF (exp), 16, port);
75 scm_putc ('>', port);
76 return 1 ;
77}
78
79static SCM
80make_jmpbuf (void)
81{
82 SCM answer;
83 SCM_NEWSMOB2 (answer, tc16_jmpbuffer, 0, 0);
84 SETJBJMPBUF(answer, (jmp_buf *)0);
85 DEACTIVATEJB(answer);
86 return answer;
87}
88
89\f
90/* scm_c_catch (the guts of catch) */
91
92struct jmp_buf_and_retval /* use only on the stack, in scm_catch */
93{
94 jmp_buf buf; /* must be first */
95 SCM throw_tag;
96 SCM retval;
97};
98
99/* These are the structures we use to store pre-unwind handling (aka
100 "lazy") information for a regular catch, and put on the wind list
101 for a "lazy" catch. They store the pre-unwind handler function to
102 call, and the data pointer to pass through to it. It's not a
103 Scheme closure, but it is a function with data, so the term
104 "closure" is appropriate in its broader sense.
105
106 (We don't need anything like this to run the normal (post-unwind)
107 catch handler, because the same C frame runs both the body and the
108 handler.) */
109
110struct pre_unwind_data {
111 scm_t_catch_handler handler;
112 void *handler_data;
113 int running;
114 int lazy_catch_p;
115};
116
117
118/* scm_c_catch is the guts of catch. It handles all the mechanics of
119 setting up a catch target, invoking the catch body, and perhaps
120 invoking the handler if the body does a throw.
121
122 The function is designed to be usable from C code, but is general
123 enough to implement all the semantics Guile Scheme expects from
124 throw.
125
126 TAG is the catch tag. Typically, this is a symbol, but this
127 function doesn't actually care about that.
128
129 BODY is a pointer to a C function which runs the body of the catch;
130 this is the code you can throw from. We call it like this:
131 BODY (BODY_DATA)
132 where:
133 BODY_DATA is just the BODY_DATA argument we received; we pass it
134 through to BODY as its first argument. The caller can make
135 BODY_DATA point to anything useful that BODY might need.
136
137 HANDLER is a pointer to a C function to deal with a throw to TAG,
138 should one occur. We call it like this:
139 HANDLER (HANDLER_DATA, THROWN_TAG, THROW_ARGS)
140 where
141 HANDLER_DATA is the HANDLER_DATA argument we recevied; it's the
142 same idea as BODY_DATA above.
143 THROWN_TAG is the tag that the user threw to; usually this is
144 TAG, but it could be something else if TAG was #t (i.e., a
145 catch-all), or the user threw to a jmpbuf.
146 THROW_ARGS is the list of arguments the user passed to the THROW
147 function, after the tag.
148
149 BODY_DATA is just a pointer we pass through to BODY. HANDLER_DATA
150 is just a pointer we pass through to HANDLER. We don't actually
151 use either of those pointers otherwise ourselves. The idea is
152 that, if our caller wants to communicate something to BODY or
153 HANDLER, it can pass a pointer to it as MUMBLE_DATA, which BODY and
154 HANDLER can then use. Think of it as a way to make BODY and
155 HANDLER closures, not just functions; MUMBLE_DATA points to the
156 enclosed variables.
157
158 Of course, it's up to the caller to make sure that any data a
159 MUMBLE_DATA needs is protected from GC. A common way to do this is
160 to make MUMBLE_DATA a pointer to data stored in an automatic
161 structure variable; since the collector must scan the stack for
162 references anyway, this assures that any references in MUMBLE_DATA
163 will be found. */
164
165SCM
166scm_c_catch (SCM tag,
167 scm_t_catch_body body, void *body_data,
168 scm_t_catch_handler handler, void *handler_data,
169 scm_t_catch_handler pre_unwind_handler, void *pre_unwind_handler_data)
170{
171 struct jmp_buf_and_retval jbr;
172 SCM jmpbuf;
173 SCM answer;
174 SCM vm;
175 SCM *sp = NULL, *fp = NULL; /* to reset the vm */
176 struct pre_unwind_data pre_unwind;
177
178 vm = scm_the_vm ();
179 if (SCM_NFALSEP (vm))
180 {
181 sp = SCM_VM_DATA (vm)->sp;
182 fp = SCM_VM_DATA (vm)->fp;
183 }
184
185 jmpbuf = make_jmpbuf ();
186 answer = SCM_EOL;
187 scm_i_set_dynwinds (scm_acons (tag, jmpbuf, scm_i_dynwinds ()));
188 SETJBJMPBUF(jmpbuf, &jbr.buf);
189 SCM_SETJBDFRAME(jmpbuf, scm_i_last_debug_frame ());
190
191 pre_unwind.handler = pre_unwind_handler;
192 pre_unwind.handler_data = pre_unwind_handler_data;
193 pre_unwind.running = 0;
194 pre_unwind.lazy_catch_p = 0;
195 SCM_SETJBPREUNWIND(jmpbuf, &pre_unwind);
196
197 if (setjmp (jbr.buf))
198 {
199 SCM throw_tag;
200 SCM throw_args;
201
202#ifdef STACK_CHECKING
203 scm_stack_checking_enabled_p = SCM_STACK_CHECKING_P;
204#endif
205 SCM_CRITICAL_SECTION_START;
206 DEACTIVATEJB (jmpbuf);
207 scm_i_set_dynwinds (SCM_CDR (scm_i_dynwinds ()));
208 SCM_CRITICAL_SECTION_END;
209 throw_args = jbr.retval;
210 throw_tag = jbr.throw_tag;
211 jbr.throw_tag = SCM_EOL;
212 jbr.retval = SCM_EOL;
213 if (SCM_NFALSEP (vm))
214 {
215 SCM_VM_DATA (vm)->sp = sp;
216 SCM_VM_DATA (vm)->fp = fp;
217#ifdef VM_ENABLE_STACK_NULLING
218 /* see vm.c -- you'll have to enable this manually */
219 memset (sp + 1, 0,
220 (SCM_VM_DATA (vm)->stack_size
221 - (sp + 1 - SCM_VM_DATA (vm)->stack_base)) * sizeof(SCM));
222#endif
223 }
224 else if (SCM_NFALSEP ((vm = scm_the_vm ())))
225 {
226 /* oof, it's possible this catch was called before the vm was
227 booted... yick. anyway, try to reset the vm stack. */
228 SCM_VM_DATA (vm)->sp = SCM_VM_DATA (vm)->stack_base - 1;
229 SCM_VM_DATA (vm)->fp = NULL;
230#ifdef VM_ENABLE_STACK_NULLING
231 /* see vm.c -- you'll have to enable this manually */
232 memset (SCM_VM_DATA (vm)->stack_base, 0,
233 SCM_VM_DATA (vm)->stack_size * sizeof(SCM));
234#endif
235 }
236
237 answer = handler (handler_data, throw_tag, throw_args);
238 }
239 else
240 {
241 ACTIVATEJB (jmpbuf);
242 answer = body (body_data);
243 SCM_CRITICAL_SECTION_START;
244 DEACTIVATEJB (jmpbuf);
245 scm_i_set_dynwinds (SCM_CDR (scm_i_dynwinds ()));
246 SCM_CRITICAL_SECTION_END;
247 }
248 return answer;
249}
250
251SCM
252scm_internal_catch (SCM tag,
253 scm_t_catch_body body, void *body_data,
254 scm_t_catch_handler handler, void *handler_data)
255{
256 return scm_c_catch(tag,
257 body, body_data,
258 handler, handler_data,
259 NULL, NULL);
260}
261
262
263\f
264/* The smob tag for pre_unwind_data smobs. */
265static scm_t_bits tc16_pre_unwind_data;
266
267/* Strictly speaking, we could just pass a zero for our print
268 function, because we don't need to print them. They should never
269 appear in normal data structures, only in the wind list. However,
270 it might be nice for debugging someday... */
271static int
272pre_unwind_data_print (SCM closure, SCM port, scm_print_state *pstate SCM_UNUSED)
273{
274 struct pre_unwind_data *c = (struct pre_unwind_data *) SCM_CELL_WORD_1 (closure);
275 char buf[200];
276
277 sprintf (buf, "#<pre-unwind-data 0x%lx 0x%lx>",
278 (long) c->handler, (long) c->handler_data);
279 scm_puts (buf, port);
280
281 return 1;
282}
283
284
285/* Given a pointer to a pre_unwind_data structure, return a smob for it,
286