Index: src/pmc/exception.pmc =================================================================== --- src/pmc/exception.pmc (revision 46609) +++ src/pmc/exception.pmc (working copy) @@ -751,7 +751,28 @@ RETURN(PMC *result); } +/* +=item C + +Discard abandoned runloops when exception handling is done. EXPERIMENTAL. + +=cut + +*/ + + METHOD rewind(INTVAL pos) { + PMC *iter; + GET_ATTR_handler_iter(INTERP, SELF, iter); + if (!PMC_IS_NULL(iter)) { + /* The active handler has been shifted, its current index + * within the iterator is -1 */ + PMC *handler = VTABLE_get_pmc_keyed_int(INTERP, iter, -1); + if (!PMC_IS_NULL(handler)) + Parrot_pcc_invoke_method_from_c_args(INTERP, handler, CONST_STRING(INTERP, "rewind"), "I->", pos); + } + } + /* =back Index: src/pmc/exceptionhandler.pmc =================================================================== --- src/pmc/exceptionhandler.pmc (revision 46609) +++ src/pmc/exceptionhandler.pmc (working copy) @@ -300,6 +300,31 @@ : PMCNULL; } +/* + +=item C + +Discard abandoned runloops when exception handling is done. EXPERIMENTAL. + +=cut + +*/ + + METHOD rewind(INTVAL pos) { + Parrot_runloop *rl = INTERP->current_runloop; + INTVAL rid; + GET_ATTR_runloop_id(INTERP, SELF, rid); + while (rl && rl->id != rid) + rl = rl->prev; + if (rl) { + rl->handler_start = (opcode_t *)pos; + longjmp(rl->resume, 3); + } + else + Parrot_ex_throw_from_c_args(INTERP, NULL, + EXCEPTION_INVALID_OPERATION, "missing runloop"); + } + } /* Index: src/call/ops.c =================================================================== --- src/call/ops.c (revision 46609) +++ src/call/ops.c (working copy) @@ -1,5 +1,5 @@ /* -Copyright (C) 2001-2009, Parrot Foundation. +Copyright (C) 2001-2010, Parrot Foundation. $Id$ =head1 NAME @@ -35,10 +35,15 @@ /* HEADERIZER BEGIN: static */ /* Don't modify between HEADERIZER BEGIN / HEADERIZER END. Your changes will be lost. */ +static void free_runloops_until(PARROT_INTERP, int id) + __attribute__nonnull__(1); + static void really_destroy_runloop_jump_points(PARROT_INTERP, ARGFREE(Parrot_runloop *jump_point)) __attribute__nonnull__(1); +#define ASSERT_ARGS_free_runloops_until __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ + PARROT_ASSERT_ARG(interp)) #define ASSERT_ARGS_really_destroy_runloop_jump_points \ __attribute__unused__ int _ASSERT_ARGS_CHECK = (\ PARROT_ASSERT_ARG(interp)) @@ -61,8 +66,8 @@ ASSERT_ARGS(runops) volatile size_t offset = offs; const int old_runloop_id = interp->current_runloop_id; - const int our_runloop_level = ++interp->current_runloop_level; - const int our_runloop_id = ++runloop_id_counter; + int our_runloop_level = interp->current_runloop_level; + int our_runloop_id = old_runloop_id; /* It is OK if the runloop ID overflows; we only ever test it for equality, so the chance of collision is slight. */ @@ -82,6 +87,8 @@ #endif { new_runloop_jump_point(interp); + our_runloop_id = interp->current_runloop_id; + our_runloop_level = interp->current_runloop_level; reenter: interp->current_runloop->handler_start = NULL; switch (setjmp(interp->current_runloop->resume)) { @@ -101,10 +108,17 @@ case 2: /* Reenter the runloop from a exception thrown from C * with a pir handler */ + free_runloops_until(interp, our_runloop_id); PARROT_ASSERT(interp->current_runloop->handler_start); offset = interp->current_runloop->handler_start - interp->code->base.data; /* Prevent incorrect reuse */ goto reenter; + case 3: + /* Reenter the runloop when finished the handling of a + * exception */ + free_runloops_until(interp, our_runloop_id); + offset = interp->current_runloop->handler_start - interp->code->base.data; + goto reenter; default: break; } @@ -121,9 +135,6 @@ fprintf(stderr, "[exiting loop %d, level %d]\n", our_runloop_id, our_runloop_level); #endif - - interp->current_runloop_level = our_runloop_level - 1; - interp->current_runloop_id = old_runloop_id; } @@ -158,8 +169,11 @@ else jump_point = mem_gc_allocate_zeroed_typed(interp, Parrot_runloop); - jump_point->prev = interp->current_runloop; - interp->current_runloop = jump_point; + jump_point->prev = interp->current_runloop; + jump_point->id = ++runloop_id_counter; + interp->current_runloop = jump_point; + interp->current_runloop_id = jump_point->id; + ++interp->current_runloop_level; } /* @@ -178,9 +192,12 @@ { ASSERT_ARGS(free_runloop_jump_point) Parrot_runloop * const jump_point = interp->current_runloop; - interp->current_runloop = jump_point->prev; + Parrot_runloop * const current = jump_point->prev; + interp->current_runloop = current; jump_point->prev = interp->runloop_jmp_free_list; interp->runloop_jmp_free_list = jump_point; + interp->current_runloop_id = current ? current->id : 0; + --interp->current_runloop_level; } /* @@ -204,6 +221,23 @@ /* +=item C + +Free runloops until the one with the provided id gets current. + +=cut + +*/ + +static void +free_runloops_until(PARROT_INTERP, int id) +{ + while (interp->current_runloop && interp->current_runloop_id != id) + free_runloop_jump_point(interp); +} + +/* + =item C Index: include/parrot/call.h =================================================================== --- include/parrot/call.h (revision 46609) +++ include/parrot/call.h (working copy) @@ -28,6 +28,7 @@ struct parrot_runloop_t *prev; /* interpreter's runloop * jump buffer stack */ opcode_t *handler_start; /* Used in exception handling */ + int id; /* runloop id */ /* let the biggest element cross the cacheline boundary */ Parrot_jump_buff resume; /* jmp_buf */