1 /*
2 Copyright (C) 2001-2015, Parrot Foundation.
3
4 =head1 NAME
5
6 src/call/ops.c
7
8 =head1 DESCRIPTION
9
10 B<Calling Ops>: Various functions that call the run loop.
11
12 =head1 FUNCTIONS
13
14 =over 4
15
16 =cut
17
18 */
19
20
21 #include "parrot/parrot.h"
22 #include "parrot/oplib/ops.h"
23 #include "pmc/pmc_continuation.h"
24 #include "parrot/runcore_api.h"
25
26 /* HEADERIZER HFILE: include/parrot/call.h */
27
28 #define STACKED_EXCEPTIONS 1
29 #define RUNLOOP_TRACE 0
30
31 /* HEADERIZER BEGIN: static */
32 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
33
34 static void free_runloops_until(PARROT_INTERP, int id)
35 __attribute__nonnull__(1);
36
37 static void really_destroy_runloop_jump_points(PARROT_INTERP,
38 ARGFREE(Parrot_runloop *jump_point))
39 __attribute__nonnull__(1);
40
41 #define ASSERT_ARGS_free_runloops_until __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
42 PARROT_ASSERT_ARG(interp))
43 #define ASSERT_ARGS_really_destroy_runloop_jump_points \
44 __attribute__unused__ int _ASSERT_ARGS_CHECK = (\
45 PARROT_ASSERT_ARG(interp))
46 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
47 /* HEADERIZER END: static */
48
49 /*
50
51 =item C<void runops(PARROT_INTERP, size_t offs)>
52
53 Run parrot ops. Set exception handler and/or resume after exception.
54
55 =cut
56
57 */
58
59 void
runops(PARROT_INTERP,size_t offs)60 runops(PARROT_INTERP, size_t offs)
61 {
62 ASSERT_ARGS(runops)
63 volatile size_t offset = offs;
64 const int old_runloop_id = interp->current_runloop_id;
65 int our_runloop_level = interp->current_runloop_level;
66 int our_runloop_id = old_runloop_id;
67
68 /* It is OK if the runloop ID overflows; we only ever test it for equality,
69 so the chance of collision is slight. */
70 interp->current_runloop_id = our_runloop_id;
71
72 #if RUNLOOP_TRACE
73 fprintf(stderr, "[entering loop %d, level %d]\n",
74 interp->current_runloop_id, our_runloop_level);
75 #endif
76
77 /*
78 * STACKED_EXCEPTIONS are necessary to catch exceptions in reentered
79 * run loops, e.g. if a delegate method throws an exception
80 */
81 #if ! STACKED_EXCEPTIONS
82 if (!interp->current_runloop)
83 #endif
84 {
85 Parrot_runloop_new_jump_point(interp);
86 our_runloop_id = interp->current_runloop_id;
87 our_runloop_level = interp->current_runloop_level;
88 reenter:
89 interp->current_runloop->handler_start = NULL;
90 switch (setjmp(interp->current_runloop->resume)) {
91 case PARROT_JMP_EXCEPTION_HANDLED:
92 /* an exception was handled */
93 if (STACKED_EXCEPTIONS)
94 Parrot_runloop_free_jump_point(interp);
95
96 interp->current_runloop_level = our_runloop_level - 1;
97 interp->current_runloop_id = old_runloop_id;
98
99 #if RUNLOOP_TRACE
100 fprintf(stderr, "[handled exception; back to loop %d, level %d]\n",
101 interp->current_runloop_id, interp->current_runloop_level);
102 #endif
103 return;
104 case PARROT_JMP_EXCEPTION_FROM_C:
105 /* Reenter the runloop from a exception thrown from C
106 * with a pir handler */
107 free_runloops_until(interp, our_runloop_id);
108 PARROT_ASSERT(interp->current_runloop->handler_start);
109 offset = interp->current_runloop->handler_start - interp->code->base.data;
110 /* Prevent incorrect reuse */
111 goto reenter;
112 case PARROT_JMP_EXCEPTION_FINALIZED:
113 /* Reenter the runloop when finished the handling of a
114 * exception */
115 free_runloops_until(interp, our_runloop_id);
116 offset = interp->current_runloop->handler_start - interp->code->base.data;
117 goto reenter;
118 default:
119 break;
120 }
121 }
122
123 runops_int(interp, offset);
124
125 interp->current_runloop->handler_start = NULL;
126 /* Remove the current runloop marker (put it on the free list). */
127 if (STACKED_EXCEPTIONS || interp->current_runloop)
128 Parrot_runloop_free_jump_point(interp);
129
130 #if RUNLOOP_TRACE
131 fprintf(stderr, "[exiting loop %d, level %d]\n",
132 our_runloop_id, our_runloop_level);
133 #endif
134 }
135
136 /*
137
138 =item C<void reset_runloop_id_counter(PARROT_INTERP)>
139
140 Reset runloop_id_counter to 0.
141 For use in outer_runloop
142
143 =cut
144
145 */
146
147 void
reset_runloop_id_counter(PARROT_INTERP)148 reset_runloop_id_counter(PARROT_INTERP)
149 {
150 ASSERT_ARGS(reset_runloop_id_counter)
151 interp->runloop_id_counter = 0;
152 }
153
154
155 /*
156
157 =back
158
159 =head2 Helper Functions
160
161 =over 4
162
163 =item C<void Parrot_runloop_new_jump_point(PARROT_INTERP)>
164
165 Create a new runloop jump point, either by allocating it or by
166 getting one from the free list.
167
168 =cut
169
170 */
171
172 PARROT_EXPORT
173 void
Parrot_runloop_new_jump_point(PARROT_INTERP)174 Parrot_runloop_new_jump_point(PARROT_INTERP)
175 {
176 ASSERT_ARGS(Parrot_runloop_new_jump_point)
177 Parrot_runloop *jump_point;
178
179 if (interp->runloop_jmp_free_list) {
180 jump_point = interp->runloop_jmp_free_list;
181 interp->runloop_jmp_free_list = jump_point->prev;
182 }
183 else
184 jump_point = mem_gc_allocate_zeroed_typed(interp, Parrot_runloop);
185
186 jump_point->prev = interp->current_runloop;
187 jump_point->id = ++interp->runloop_id_counter;
188 interp->current_runloop = jump_point;
189 interp->current_runloop_id = jump_point->id;
190 ++interp->current_runloop_level;
191 }
192
193 /*
194
195 =item C<void Parrot_runloop_free_jump_point(PARROT_INTERP)>
196
197 Place runloop jump point back on the free list.
198
199 =cut
200
201 */
202
203 PARROT_EXPORT
204 void
Parrot_runloop_free_jump_point(PARROT_INTERP)205 Parrot_runloop_free_jump_point(PARROT_INTERP)
206 {
207 ASSERT_ARGS(Parrot_runloop_free_jump_point)
208 Parrot_runloop * const jump_point = interp->current_runloop;
209 Parrot_runloop * const current = jump_point->prev;
210 interp->current_runloop = current;
211 jump_point->prev = interp->runloop_jmp_free_list;
212 interp->runloop_jmp_free_list = jump_point;
213 interp->current_runloop_id = current ? current->id : 0;
214 --interp->current_runloop_level;
215 }
216
217 /*
218
219 =item C<void new_runloop_jump_point(PARROT_INTERP)>
220
221 This name is deprecated, use C<Parrot_runloop_new_jump_point> instead.
222
223 =cut
224
225 */
226
227 PARROT_EXPORT
228 PARROT_DEPRECATED
229 void
new_runloop_jump_point(PARROT_INTERP)230 new_runloop_jump_point(PARROT_INTERP)
231 {
232 ASSERT_ARGS(new_runloop_jump_point)
233 Parrot_runloop_new_jump_point(interp);
234 }
235
236 /*
237
238 =item C<void free_runloop_jump_point(PARROT_INTERP)>
239
240 This name is deprecated, use C<Parrot_runloop_free_jump_point> instead.
241
242 =cut
243
244 */
245
246 PARROT_EXPORT
247 PARROT_DEPRECATED
248 void
free_runloop_jump_point(PARROT_INTERP)249 free_runloop_jump_point(PARROT_INTERP)
250 {
251 ASSERT_ARGS(free_runloop_jump_point)
252 Parrot_runloop_free_jump_point(interp);
253 }
254
255 /*
256
257 =item C<void destroy_runloop_jump_points(PARROT_INTERP)>
258
259 Destroys (and frees the memory of) the runloop jump point list and the
260 associated free list for the specified interpreter.
261
262 =cut
263
264 */
265
266 void
destroy_runloop_jump_points(PARROT_INTERP)267 destroy_runloop_jump_points(PARROT_INTERP)
268 {
269 ASSERT_ARGS(destroy_runloop_jump_points)
270 really_destroy_runloop_jump_points(interp, interp->current_runloop);
271 really_destroy_runloop_jump_points(interp, interp->runloop_jmp_free_list);
272 }
273
274 /*
275
276 =item C<static void free_runloops_until(PARROT_INTERP, int id)>
277
278 Free runloops until the one with the provided id gets current.
279
280 =cut
281
282 */
283
284 static void
free_runloops_until(PARROT_INTERP,int id)285 free_runloops_until(PARROT_INTERP, int id)
286 {
287 ASSERT_ARGS(free_runloops_until)
288 while (interp->current_runloop && interp->current_runloop_id != id)
289 Parrot_runloop_free_jump_point(interp);
290 }
291
292 /*
293
294 =item C<static void really_destroy_runloop_jump_points(PARROT_INTERP,
295 Parrot_runloop *jump_point)>
296
297 Takes a pointer to a runloop jump point (which had better be the last one in
298 the list). Walks back through the list, freeing the memory of each one, until
299 it encounters NULL. Used by C<destroy_runloop_jump_points>.
300
301 =cut
302
303 */
304
305 static void
really_destroy_runloop_jump_points(PARROT_INTERP,ARGFREE (Parrot_runloop * jump_point))306 really_destroy_runloop_jump_points(PARROT_INTERP,
307 ARGFREE(Parrot_runloop *jump_point))
308 {
309 ASSERT_ARGS(really_destroy_runloop_jump_points)
310 while (jump_point) {
311 Parrot_runloop * const prev = jump_point->prev;
312 mem_gc_free(interp, jump_point);
313 jump_point = prev;
314 }
315 }
316
317
318 /*
319
320 =back
321
322 =head1 SEE ALSO
323
324 F<include/parrot/interpreter.h>, F<src/interpreter.c>.
325
326 =cut
327
328 */
329
330 /*
331 * Local variables:
332 * c-file-style: "parrot"
333 * End:
334 * vim: expandtab shiftwidth=4 cinoptions='\:2=2' :
335 */
336