Starting release 0.7.0
[parrot.git] / src / inter_run.c
blobd0a1c6408ae5be43cec50411a8c3c0e10a9185ac
1 /*
2 Copyright (C) 2001-2008, The Perl Foundation.
3 $Id$
5 =head1 NAME
7 src/inter_run.c - Parrot Interpreter - Run Ops and Methods
9 =head1 DESCRIPTION
11 Various functions that call the run loop.
13 =head2 Functions
15 =over 4
17 =cut
22 #include "parrot/parrot.h"
23 #include "parrot/oplib/ops.h"
25 /* HEADERIZER HFILE: include/parrot/interpreter.h */
27 /* HEADERIZER BEGIN: static */
28 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
30 PARROT_WARN_UNUSED_RESULT
31 PARROT_CANNOT_RETURN_NULL
32 static parrot_context_t * runops_args(PARROT_INTERP,
33 ARGIN(PMC *sub),
34 ARGIN_NULLOK(PMC *obj),
35 SHIM(STRING *meth),
36 ARGIN(const char *sig),
37 va_list ap)
38 __attribute__nonnull__(1)
39 __attribute__nonnull__(2)
40 __attribute__nonnull__(5);
42 /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */
43 /* HEADERIZER END: static */
45 #define STACKED_EXCEPTIONS 1
46 /* #define RUNLOOP_TRACE 1 */
48 static int
49 runloop_id_counter = 0; /* for synthesizing runloop ids. */
53 =item C<void runops>
55 Run parrot ops. Set exception handler and/or resume after exception.
57 =cut
61 void
62 runops(PARROT_INTERP, size_t offs)
64 volatile size_t offset = offs;
65 const int old_runloop_id = interp->current_runloop_id;
66 const int our_runloop_level = ++interp->current_runloop_level;
67 const int our_runloop_id = ++runloop_id_counter;
69 /* It is OK if the runloop ID overflows; we only ever test it for equality,
70 so the chance of collision is slight. */
71 interp->current_runloop_id = our_runloop_id;
72 #ifdef RUNLOOP_TRACE
73 fprintf(stderr, "[entering loop %d, level %d]\n",
74 interp->current_runloop_id, our_runloop_level);
75 #endif
77 * STACKED_EXCEPTIONS are necessary to catch exceptions in reentered
78 * run loops, e.g. if a delegate methods throws an exception
80 #if ! STACKED_EXCEPTIONS
81 if (!interp->current_runloop)
82 #endif
84 new_runloop_jump_point(interp);
85 if (setjmp(interp->current_runloop->resume)) {
86 /* an exception was handled */
87 if (STACKED_EXCEPTIONS) {
88 free_runloop_jump_point(interp);
90 interp->current_runloop_level = our_runloop_level - 1;
91 interp->current_runloop_id = old_runloop_id;
93 #ifdef RUNLOOP_TRACE
94 fprintf(stderr, "[handled exception; back to loop %d, level %d]\n",
95 interp->current_runloop_id, interp->current_runloop_level);
96 #endif
97 return;
101 runops_int(interp, offset);
103 /* Remove the current runloop marker (put it on the free list). */
104 if (STACKED_EXCEPTIONS) {
105 free_runloop_jump_point(interp);
107 #ifdef RUNLOOP_TRACE
108 fprintf(stderr, "[exiting loop %d, level %d]\n",
109 our_runloop_id, our_runloop_level);
110 #endif
111 interp->current_runloop_level = our_runloop_level - 1;
112 interp->current_runloop_id = old_runloop_id;
117 =item C<parrot_context_t * Parrot_runops_fromc>
119 Runs the Parrot ops, called from C code. The function arguments are
120 already setup according to Parrot calling conventions, the C<sub> argument
121 is an invocable C<Sub> PMC.
123 =cut
127 PARROT_API
128 PARROT_IGNORABLE_RESULT
129 PARROT_CANNOT_RETURN_NULL
130 parrot_context_t *
131 Parrot_runops_fromc(PARROT_INTERP, ARGIN(PMC *sub))
133 opcode_t offset, *dest;
134 parrot_context_t *ctx;
136 /* we need one return continuation with a NULL offset */
137 PMC * const ret_c = new_ret_continuation_pmc(interp, NULL);
138 interp->current_cont = ret_c;
139 #if defined GC_VERBOSE && GC_VERBOSE
140 PObj_report_SET(ret_c); /* s. also dod.c */
141 #endif
142 /* invoke the sub, which places the context of the sub in the
143 * interpreter, and switches code segments if needed
144 * Passing a dummy true destination copies registers
146 dest = VTABLE_invoke(interp, sub, (void*) 1);
147 if (!dest)
148 Parrot_ex_throw_from_c_args(interp, NULL, 1,
149 "Subroutine returned a NULL address");
151 ctx = CONTEXT(interp);
152 offset = dest - interp->code->base.data;
153 runops(interp, offset);
154 return ctx;
160 =item C<static parrot_context_t * runops_args>
162 RT#48260: Not yet documented!!!
164 =cut
168 PARROT_WARN_UNUSED_RESULT
169 PARROT_CANNOT_RETURN_NULL
170 static parrot_context_t *
171 runops_args(PARROT_INTERP, ARGIN(PMC *sub), ARGIN_NULLOK(PMC *obj),
172 SHIM(STRING *meth), ARGIN(const char *sig), va_list ap)
174 opcode_t offset, *dest;
175 parrot_context_t *ctx;
177 char new_sig[10];
178 const char *sig_p;
179 parrot_context_t * const old_ctx = CONTEXT(interp);
181 interp->current_cont = new_ret_continuation_pmc(interp, NULL);
182 interp->current_object = obj;
183 dest = VTABLE_invoke(interp, sub, NULL);
184 if (!dest)
185 Parrot_ex_throw_from_c_args(interp, NULL, 1,
186 "Subroutine returned a NULL address");
188 if (PMC_IS_NULL(obj)) {
189 /* skip over the return type */
190 sig_p = sig + 1;
192 else if (sig[1] == 'O') {
193 /* skip over the return type */
194 sig_p = sig + 1;
196 else {
197 const size_t len = strlen(sig);
198 if (len > 8)
199 Parrot_ex_throw_from_c_args(interp, NULL, 1,
200 "too many arguments in runops_args");
202 new_sig[0] = 'O';
203 strcpy(new_sig + 1, sig + 1);
204 sig_p = new_sig;
207 if (*sig_p && (dest[0] == PARROT_OP_get_params_pc
208 || (sub->vtable->base_type == enum_class_ExceptionHandler
209 && PMC_cont(sub)->current_results))) {
210 dest = parrot_pass_args_fromc(interp, sig_p, dest, old_ctx, ap);
213 * main is now started with runops_args_fromc too
214 * PASM subs usually don't have get_params
215 * XXX we could check, if we are running main
216 else
217 Parrot_ex_throw_from_c_args(interp, NULL, EXCEPTION_INVALID_OPERATION,
218 "no get_params in sub");
221 ctx = CONTEXT(interp);
222 offset = dest - interp->code->base.data;
223 runops(interp, offset);
224 return ctx;
230 =item C<void * Parrot_run_meth_fromc>
232 Run a method sub from C. The function arguments are
233 already setup according to Parrot calling conventions, the C<sub> argument
234 is an invocable C<Sub> PMC.
236 If registers a PMC return values, it is returned.
238 =cut
242 PARROT_API
243 PARROT_IGNORABLE_RESULT
244 PARROT_CAN_RETURN_NULL
245 void *
246 Parrot_run_meth_fromc(PARROT_INTERP, ARGIN(PMC *sub), ARGIN_NULLOK(PMC *obj), SHIM(STRING *meth))
248 parrot_context_t *ctx;
249 opcode_t offset, *dest;
251 interp->current_cont = new_ret_continuation_pmc(interp, NULL);
252 interp->current_object = obj;
253 dest = VTABLE_invoke(interp, sub, (void *)1);
255 if (!dest)
256 Parrot_ex_throw_from_c_args(interp, NULL, 1,
257 "Subroutine returned a NULL address");
259 ctx = CONTEXT(interp);
260 offset = dest - interp->code->base.data;
261 runops(interp, offset);
262 return set_retval(interp, 0, ctx);
267 =item C<PMC * Parrot_runops_fromc_args>
269 Run parrot ops, called from C code, function arguments are passed as
270 C<va_args> according to the signature. The C<sub> argument is an
271 invocable C<Sub> PMC.
273 Signatures are similar to NCI:
275 v ... void return
276 I ... INTVAL (not Interpreter)
277 N ... NUMVAL
278 S ... STRING*
279 P ... PMC*
281 =cut
285 PARROT_API
286 PARROT_IGNORABLE_RESULT
287 PARROT_CAN_RETURN_NULL
288 PMC *
289 Parrot_runops_fromc_args(PARROT_INTERP, ARGIN(PMC *sub), ARGIN(const char *sig), ...)
291 va_list args;
292 parrot_context_t *ctx;
294 va_start(args, sig);
295 ctx = runops_args(interp, sub, PMCNULL, NULL, sig, args);
296 va_end(args);
297 return (PMC *)set_retval(interp, *sig, ctx);
302 =item C<void * Parrot_runops_fromc_args_event>
304 Run code from within event handlers. This variant deals with some reentrency
305 issues. It also should do sanity checks, if e.g. the handler subroutine
306 didn't return properly.
308 =cut
312 PARROT_API
313 PARROT_IGNORABLE_RESULT
314 PARROT_CAN_RETURN_NULL
315 void *
316 Parrot_runops_fromc_args_event(PARROT_INTERP, ARGIN(PMC *sub),
317 ARGIN(const char *sig), ...)
319 va_list args;
320 parrot_context_t *ctx;
321 void *retval;
323 * running code from event handlers isn't fully reentrant due to
324 * these interpreter variables - mainly related to calls
326 opcode_t * const cargs = interp->current_args;
327 opcode_t * const params = interp->current_params;
328 opcode_t * const returns = interp->current_returns;
329 PMC * const cont = interp->current_cont;
330 /* what else ? */
332 va_start(args, sig);
333 ctx = runops_args(interp, sub, PMCNULL, NULL, sig, args);
334 va_end(args);
335 retval = set_retval(interp, *sig, ctx);
337 interp->current_args = cargs;
338 interp->current_params = params;
339 interp->current_returns = returns;
340 interp->current_cont = cont;
341 return retval;
346 =item C<INTVAL Parrot_runops_fromc_args_reti>
348 RT#48260: Not yet documented!!!
350 =cut
354 PARROT_API
355 PARROT_IGNORABLE_RESULT
356 INTVAL
357 Parrot_runops_fromc_args_reti(PARROT_INTERP, ARGIN(PMC *sub),
358 ARGIN(const char *sig), ...)
360 va_list args;
361 parrot_context_t *ctx;
363 va_start(args, sig);
364 ctx = runops_args(interp, sub, PMCNULL, NULL, sig, args);
365 va_end(args);
366 return set_retval_i(interp, *sig, ctx);
371 =item C<FLOATVAL Parrot_runops_fromc_args_retf>
373 RT#48260: Not yet documented!!!
375 =cut
379 PARROT_API
380 PARROT_IGNORABLE_RESULT
381 FLOATVAL
382 Parrot_runops_fromc_args_retf(PARROT_INTERP, ARGIN(PMC *sub),
383 ARGIN(const char *sig), ...)
385 va_list args;
386 parrot_context_t *ctx;
388 va_start(args, sig);
389 ctx = runops_args(interp, sub, PMCNULL, NULL, sig, args);
390 va_end(args);
391 return set_retval_f(interp, *sig, ctx);
396 =item C<void* Parrot_run_meth_fromc_args>
398 RT#48260: Not yet documented!!!
400 =cut
404 PARROT_API
405 PARROT_IGNORABLE_RESULT
406 PARROT_CAN_RETURN_NULL
407 void*
408 Parrot_run_meth_fromc_args(PARROT_INTERP, ARGIN(PMC *sub), ARGIN_NULLOK(PMC *obj),
409 ARGIN(STRING *meth), ARGIN(const char *sig), ...)
411 va_list args;
412 parrot_context_t *ctx;
414 va_start(args, sig);
415 ctx = runops_args(interp, sub, obj, meth, sig, args);
416 va_end(args);
417 return set_retval(interp, *sig, ctx);
422 =item C<INTVAL Parrot_run_meth_fromc_args_reti>
424 RT#48260: Not yet documented!!!
426 =cut
430 PARROT_API
431 PARROT_IGNORABLE_RESULT
432 INTVAL
433 Parrot_run_meth_fromc_args_reti(PARROT_INTERP, ARGIN(PMC *sub), ARGIN_NULLOK(PMC *obj),
434 ARGIN(STRING *meth), ARGIN(const char *sig), ...)
436 va_list args;
437 parrot_context_t *ctx;
439 va_start(args, sig);
440 ctx = runops_args(interp, sub, obj, meth, sig, args);
441 va_end(args);
442 return set_retval_i(interp, *sig, ctx);
447 =item C<FLOATVAL Parrot_run_meth_fromc_args_retf>
449 RT#48260: Not yet documented!!!
451 =cut
455 PARROT_API
456 PARROT_IGNORABLE_RESULT
457 FLOATVAL
458 Parrot_run_meth_fromc_args_retf(PARROT_INTERP, ARGIN(PMC *sub), ARGIN_NULLOK(PMC *obj),
459 ARGIN(STRING *meth), ARGIN(const char *sig), ...)
461 va_list args;
462 parrot_context_t *ctx;
464 va_start(args, sig);
465 ctx = runops_args(interp, sub, obj, meth, sig, args);
466 va_end(args);
467 return set_retval_f(interp, *sig, ctx);
472 =item C<void * Parrot_runops_fromc_arglist>
474 RT#48260: Not yet documented!!!
476 =cut
480 PARROT_API
481 PARROT_IGNORABLE_RESULT
482 PARROT_CAN_RETURN_NULL
483 void *
484 Parrot_runops_fromc_arglist(PARROT_INTERP, ARGIN(PMC *sub),
485 ARGIN(const char *sig), va_list args)
487 parrot_context_t * const ctx = runops_args(interp, sub, PMCNULL, NULL, sig, args);
489 return set_retval(interp, *sig, ctx);
494 =item C<INTVAL Parrot_runops_fromc_arglist_reti>
496 RT#48260: Not yet documented!!!
498 =cut
502 PARROT_API
503 PARROT_IGNORABLE_RESULT
504 INTVAL
505 Parrot_runops_fromc_arglist_reti(PARROT_INTERP, ARGIN(PMC *sub),
506 ARGIN(const char *sig), va_list args)
508 parrot_context_t * const ctx = runops_args(interp, sub, PMCNULL, NULL, sig, args);
510 return set_retval_i(interp, *sig, ctx);
515 =item C<FLOATVAL Parrot_runops_fromc_arglist_retf>
517 RT#48260: Not yet documented!!!
519 =cut
523 PARROT_API
524 PARROT_IGNORABLE_RESULT
525 FLOATVAL
526 Parrot_runops_fromc_arglist_retf(PARROT_INTERP, ARGIN(PMC *sub),
527 ARGIN(const char *sig), va_list args)
529 parrot_context_t * const ctx = runops_args(interp, sub, PMCNULL, NULL, sig, args);
531 return set_retval_f(interp, *sig, ctx);
536 =item C<void* Parrot_run_meth_fromc_arglist>
538 RT#48260: Not yet documented!!!
540 =cut
544 PARROT_API
545 PARROT_IGNORABLE_RESULT
546 PARROT_CAN_RETURN_NULL
547 void*
548 Parrot_run_meth_fromc_arglist(PARROT_INTERP, ARGIN(PMC *sub), ARGIN_NULLOK(PMC *obj),
549 ARGIN(STRING *meth), ARGIN(const char *sig), va_list args)
551 parrot_context_t *ctx;
553 ctx = runops_args(interp, sub, obj, meth, sig, args);
554 return set_retval(interp, *sig, ctx);
559 =item C<INTVAL Parrot_run_meth_fromc_arglist_reti>
561 RT#48260: Not yet documented!!!
563 =cut
567 PARROT_API
568 PARROT_IGNORABLE_RESULT
569 PARROT_CAN_RETURN_NULL
570 INTVAL
571 Parrot_run_meth_fromc_arglist_reti(PARROT_INTERP, ARGIN(PMC *sub), ARGIN_NULLOK(PMC *obj),
572 ARGIN(STRING *meth), ARGIN(const char *sig), va_list args)
574 parrot_context_t * const ctx = runops_args(interp, sub, obj, meth, sig, args);
576 return set_retval_i(interp, *sig, ctx);
581 =item C<FLOATVAL Parrot_run_meth_fromc_arglist_retf>
583 RT#48260: Not yet documented!!!
585 =cut
589 PARROT_API
590 PARROT_IGNORABLE_RESULT
591 FLOATVAL
592 Parrot_run_meth_fromc_arglist_retf(PARROT_INTERP, ARGIN(PMC *sub), ARGIN_NULLOK(PMC *obj),
593 ARGIN(STRING *meth), ARGIN(const char *sig), va_list args)
595 parrot_context_t * const ctx = runops_args(interp, sub, obj, meth, sig, args);
596 return set_retval_f(interp, *sig, ctx);
601 =back
603 =head2 Helper Functions
605 =over 4
607 =item C<void new_runloop_jump_point>
609 Create a new runloop jump point, either by allocating it or by
610 getting one from the free list.
612 =cut
616 PARROT_API
617 void
618 new_runloop_jump_point(PARROT_INTERP)
620 Parrot_runloop *jump_point;
622 if (interp->runloop_jmp_free_list) {
623 jump_point = interp->runloop_jmp_free_list;
624 interp->runloop_jmp_free_list = jump_point->prev;
626 else
627 jump_point = mem_allocate_typed(Parrot_runloop);
629 jump_point->prev = interp->current_runloop;
630 interp->current_runloop = jump_point;
635 =item C<void free_runloop_jump_point>
637 Place runloop jump point back on the free list.
639 =cut
643 PARROT_API
644 void
645 free_runloop_jump_point(PARROT_INTERP)
647 Parrot_runloop * const jump_point = interp->current_runloop;
648 interp->current_runloop = jump_point->prev;
649 jump_point->prev = interp->runloop_jmp_free_list;
650 interp->runloop_jmp_free_list = jump_point;
655 =item C<void destroy_runloop_jump_points>
657 Destroys (and frees the memory of) the runloop jump point list and the
658 associated free list for the specified interpreter.
660 =cut
664 void
665 destroy_runloop_jump_points(PARROT_INTERP)
667 really_destroy_runloop_jump_points(interp->current_runloop);
668 really_destroy_runloop_jump_points(interp->runloop_jmp_free_list);
673 =item C<void really_destroy_runloop_jump_points>
675 Takes a pointer to a runloop jump point (which had better be the last one in
676 the list). Walks back through the list, freeing the memory of each one, until
677 it encounters NULL. Used by C<destroy_runloop_jump_points>.
679 =cut
683 void
684 really_destroy_runloop_jump_points(ARGIN_NULLOK(Parrot_runloop *jump_point))
686 while (jump_point) {
687 Parrot_runloop * const prev = jump_point->prev;
688 mem_sys_free(jump_point);
689 jump_point = prev;
696 =back
698 =head1 SEE ALSO
700 F<include/parrot/interpreter.h>, F<src/interpreter.c>.
702 =cut
707 * Local variables:
708 * c-file-style: "parrot"
709 * End:
710 * vim: expandtab shiftwidth=4: