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