Commit | Line | Data |
---|---|---|
9ede013f AW |
1 | /* classes: h_files */ |
2 | ||
3 | #ifndef SCM_DYNSTACK_H | |
4 | #define SCM_DYNSTACK_H | |
5 | ||
6 | /* Copyright (C) 2012 Free Software Foundation, Inc. | |
7 | * | |
8 | * This library is free software; you can redistribute it and/or | |
9 | * modify it under the terms of the GNU Lesser General Public License | |
10 | * as published by the Free Software Foundation; either version 3 of | |
11 | * the License, or (at your option) any later version. | |
12 | * | |
13 | * This library is distributed in the hope that it will be useful, but | |
14 | * WITHOUT ANY WARRANTY; without even the implied warranty of | |
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
16 | * Lesser General Public License for more details. | |
17 | * | |
18 | * You should have received a copy of the GNU Lesser General Public | |
19 | * License along with this library; if not, write to the Free Software | |
20 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA | |
21 | * 02110-1301 USA | |
22 | */ | |
23 | ||
24 | \f | |
25 | ||
26 | #include "libguile/__scm.h" | |
27 | #include "libguile/control.h" | |
28 | ||
29 | \f | |
30 | ||
31 | typedef struct | |
32 | { | |
33 | scm_t_bits *base; | |
34 | scm_t_bits *top; | |
35 | scm_t_bits *limit; | |
36 | } scm_t_dynstack; | |
37 | ||
38 | \f | |
39 | ||
40 | /* Items on the dynstack are preceded by two-word headers, giving the | |
41 | offset of the preceding item (or 0 if there is none) and the type, | |
42 | flags, and length of the following dynstack entry, in words. In | |
43 | addition, there is a "null header" at the top of the stack, | |
44 | indicating the length of the previous item, but with a tag of zero. | |
45 | ||
46 | For example, consider an empty dynstack, with a capacity of 6 words: | |
47 | ||
48 | +----------+----------+ + | |
49 | |prev=0 |tag=0 | | | |
50 | +----------+----------+ + | |
51 | ^base ^top limit^ | |
52 | ||
53 | Now we evaluate (dynamic-wind enter thunk leave). That will result | |
54 | in a dynstack of: | |
55 | ||
56 | / the len=2 words \ | |
57 | +----------+----------+----------+----------+----------+----------+ | |
58 | |prev=0 |tag:len=2 |enter |leave |prev=4 |tag=0 | | |
59 | +----------+----------+----------+----------+----------+----------+ | |
60 | ^base top,limit^ | |
61 | ||
62 | The tag is a combination of the type of the dynstack item, some flags | |
63 | associated with the item, and the length of the item. See | |
64 | SCM_MAKE_DYNSTACK_TAG below for the details. | |
65 | ||
66 | This arrangement makes it possible to have variable-length dynstack | |
67 | items, and yet be able to traverse them forwards or backwards. */ | |
68 | ||
69 | #define SCM_DYNSTACK_HEADER_LEN 2 | |
70 | ||
71 | #define SCM_DYNSTACK_PREV_OFFSET(top) ((top)[-2]) | |
72 | #define SCM_DYNSTACK_SET_PREV_OFFSET(top, offset) (top)[-2] = (offset) | |
73 | ||
74 | #define SCM_DYNSTACK_TAG(top) ((top)[-1]) | |
75 | #define SCM_DYNSTACK_SET_TAG(top, tag) (top)[-1] = (tag) | |
76 | ||
77 | typedef enum { | |
78 | SCM_DYNSTACK_TYPE_NONE = 0, | |
79 | SCM_DYNSTACK_TYPE_FRAME, | |
80 | SCM_DYNSTACK_TYPE_UNWINDER, | |
81 | SCM_DYNSTACK_TYPE_REWINDER, | |
82 | SCM_DYNSTACK_TYPE_WITH_FLUIDS, | |
83 | SCM_DYNSTACK_TYPE_PROMPT, | |
84 | SCM_DYNSTACK_TYPE_DYNWIND, | |
85 | } scm_t_dynstack_item_type; | |
86 | ||
87 | #define SCM_DYNSTACK_TAG_TYPE_MASK 0xf | |
88 | #define SCM_DYNSTACK_TAG_FLAGS_MASK 0xf0 | |
89 | #define SCM_DYNSTACK_TAG_FLAGS_SHIFT 4 | |
90 | #define SCM_DYNSTACK_TAG_LEN_SHIFT 8 | |
91 | ||
92 | #define SCM_MAKE_DYNSTACK_TAG(type, flags, len) \ | |
93 | ((type) | (flags) | ((len) << SCM_DYNSTACK_TAG_LEN_SHIFT)) | |
94 | ||
95 | #define SCM_DYNSTACK_TAG_TYPE(tag) \ | |
96 | ((tag) & SCM_DYNSTACK_TAG_TYPE_MASK) | |
97 | #define SCM_DYNSTACK_TAG_FLAGS(tag) \ | |
98 | ((tag) & SCM_DYNSTACK_TAG_FLAGS_MASK) | |
99 | #define SCM_DYNSTACK_TAG_LEN(tag) \ | |
100 | ((tag) >> SCM_DYNSTACK_TAG_LEN_SHIFT) | |
101 | ||
102 | #define SCM_DYNSTACK_PREV(top) \ | |
103 | (SCM_DYNSTACK_PREV_OFFSET (top) \ | |
104 | ? ((top) - SCM_DYNSTACK_PREV_OFFSET (top)) : NULL) | |
105 | #define SCM_DYNSTACK_NEXT(top) \ | |
106 | (SCM_DYNSTACK_TAG (top) \ | |
107 | ? ((top) + SCM_DYNSTACK_TAG_LEN (SCM_DYNSTACK_TAG (top)) \ | |
108 | + SCM_DYNSTACK_HEADER_LEN) \ | |
109 | : NULL) | |
110 | ||
111 | #define SCM_DYNSTACK_FIRST(dynstack) \ | |
112 | ((dynstack)->base + SCM_DYNSTACK_HEADER_LEN) | |
113 | ||
114 | #define SCM_DYNSTACK_CAPACITY(dynstack) \ | |
115 | ((dynstack)->limit - (dynstack)->base) | |
116 | #define SCM_DYNSTACK_SPACE(dynstack) \ | |
117 | ((dynstack)->limit - (dynstack)->top) | |
118 | #define SCM_DYNSTACK_HEIGHT(dynstack) \ | |
119 | ((dynstack)->top - (dynstack)->base) | |
120 | ||
121 | #define SCM_DYNSTACK_HAS_SPACE(dynstack, n) \ | |
122 | (SCM_DYNSTACK_SPACE (dynstack) >= n + SCM_DYNSTACK_HEADER_LEN) | |
123 | ||
124 | typedef enum { | |
125 | SCM_F_DYNSTACK_FRAME_REWINDABLE = (1 << SCM_DYNSTACK_TAG_FLAGS_SHIFT) | |
126 | } scm_t_dynstack_frame_flags; | |
127 | ||
128 | typedef enum { | |
129 | SCM_F_DYNSTACK_WINDER_EXPLICIT = (1 << SCM_DYNSTACK_TAG_FLAGS_SHIFT) | |
130 | } scm_t_dynstack_winder_flags; | |
131 | ||
132 | typedef enum { | |
133 | SCM_F_DYNSTACK_PROMPT_ESCAPE_ONLY = (1 << SCM_DYNSTACK_TAG_FLAGS_SHIFT) | |
134 | } scm_t_dynstack_prompt_flags; | |
135 | ||
136 | typedef void (*scm_t_guard) (void *); | |
137 | ||
138 | ||
139 | \f | |
140 | ||
141 | /* Pushing and popping entries on the dynamic stack. */ | |
142 | ||
143 | SCM_INTERNAL void scm_dynstack_push_frame (scm_t_dynstack *, | |
144 | scm_t_dynstack_frame_flags); | |
145 | SCM_INTERNAL void scm_dynstack_push_rewinder (scm_t_dynstack *, | |
146 | scm_t_dynstack_winder_flags, | |
147 | scm_t_guard, void *); | |
148 | SCM_INTERNAL void scm_dynstack_push_unwinder (scm_t_dynstack *, | |
149 | scm_t_dynstack_winder_flags, | |
150 | scm_t_guard, void *); | |
151 | SCM_INTERNAL void scm_dynstack_push_fluids (scm_t_dynstack *, | |
152 | size_t, | |
153 | SCM *fluids, | |
154 | SCM *values, | |
155 | SCM dynamic_state); | |
156 | SCM_INTERNAL void scm_dynstack_push_prompt (scm_t_dynstack *, | |
157 | scm_t_dynstack_prompt_flags, | |
158 | SCM key, | |
9d381ba4 AW |
159 | SCM *fp, SCM *sp, scm_t_uint8 *ip, |
160 | scm_i_jmp_buf *registers); | |
9ede013f AW |
161 | SCM_INTERNAL void scm_dynstack_push_dynwind (scm_t_dynstack *, |
162 | SCM enter, SCM leave); | |
163 | ||
164 | SCM_INTERNAL void scm_dynstack_pop (scm_t_dynstack *); | |
165 | ||
166 | ||
167 | \f | |
168 | ||
169 | /* Capturing, winding, and unwinding. */ | |
170 | ||
171 | SCM_INTERNAL scm_t_dynstack* scm_dynstack_capture_all (scm_t_dynstack *dynstack); | |
172 | SCM_INTERNAL scm_t_dynstack* scm_dynstack_capture (scm_t_dynstack *dynstack, | |
173 | scm_t_bits *item); | |
174 | ||
175 | SCM_INTERNAL void scm_dynstack_wind_1 (scm_t_dynstack *, scm_t_bits *); | |
176 | SCM_INTERNAL scm_t_bits scm_dynstack_unwind_1 (scm_t_dynstack *); | |
177 | ||
178 | SCM_INTERNAL void scm_dynstack_wind (scm_t_dynstack *, scm_t_bits *); | |
179 | SCM_INTERNAL void scm_dynstack_unwind (scm_t_dynstack *, scm_t_bits *); | |
180 | ||
9d381ba4 AW |
181 | |
182 | \f | |
183 | ||
184 | /* Miscellany. */ | |
185 | ||
9ede013f AW |
186 | SCM_INTERNAL scm_t_bits* scm_dynstack_unwind_fork (scm_t_dynstack *, |
187 | scm_t_dynstack *); | |
188 | ||
189 | SCM_INTERNAL void scm_dynstack_unwind_frame (scm_t_dynstack *); | |
190 | SCM_INTERNAL void scm_dynstack_unwind_fluids (scm_t_dynstack *dynstack, | |
191 | SCM dynamic_state); | |
192 | ||
9ede013f | 193 | SCM_INTERNAL scm_t_bits* scm_dynstack_find_prompt (scm_t_dynstack *, SCM, |
9d381ba4 AW |
194 | scm_t_dynstack_prompt_flags *, |
195 | SCM **, SCM **, scm_t_uint8 **, | |
196 | scm_i_jmp_buf **); | |
9ede013f | 197 | |
9d381ba4 AW |
198 | SCM_INTERNAL void scm_dynstack_wind_prompt (scm_t_dynstack *, scm_t_bits *, |
199 | scm_t_ptrdiff, scm_i_jmp_buf *); | |
9ede013f AW |
200 | |
201 | ||
202 | #endif /* SCM_DYNSTACK_H */ | |
203 | ||
204 | /* | |
205 | Local Variables: | |
206 | c-file-style: "gnu" | |
207 | End: | |
208 | */ |