Index: src/ops/experimental.ops =================================================================== --- src/ops/experimental.ops (revision 46609) +++ src/ops/experimental.ops (working copy) @@ -367,6 +367,46 @@ #endif } +=item B(in PMC) + +Exception handling done, unroll possible inner runloops left. $1 is the +Exception handled or the ExceptionHandler that is handling it. +EXPERIMENTAL. Handle with care. + +=cut + +op unroll(in PMC) { + /* Go to the next op after loop unrolling */ + opcode_t * const dest = expr NEXT(); + PMC *eh = PMCNULL; + if (!PMC_IS_NULL($1)) { + /* If isa ExceptionHandler, use it. If isa Exception, get its active handler */ + if (VTABLE_isa(interp, $1, Parrot_str_new_constant(interp, "ExceptionHandler"))) + eh = $1; + else if (VTABLE_isa(interp, $1, Parrot_str_new_constant(interp, "Exception"))) { + PMC *iter = VTABLE_get_attr_str(interp, $1, Parrot_str_new_constant(interp, "handler_iter")); + if (!PMC_IS_NULL(iter)) + eh = VTABLE_get_pmc_keyed_int(interp, iter, -1); + } + } + if (!PMC_IS_NULL(eh)) { + /* Get the runloop_id from the continuation and jump to it. */ + Parrot_runloop *rl = interp->current_runloop; + INTVAL rid; + Parrot_pcc_invoke_method_from_c_args(interp, eh, Parrot_str_new_constant(interp, "rid"), "->I", &rid); + while (rl && rl->id != rid) + rl = rl->prev; + if (rl) { + rl->handler_start = dest; + longjmp(rl->resume, 3); + } + else + Parrot_ex_throw_from_c_args(interp, NULL, + EXCEPTION_INVALID_OPERATION, "missing runloop"); + } +} + + =back =head1 COPYRIGHT Index: src/pmc/continuation.pmc =================================================================== --- src/pmc/continuation.pmc (revision 46609) +++ src/pmc/continuation.pmc (working copy) @@ -294,6 +294,22 @@ /* +=item C + +Experimental: return the runloop_id value. + +=cut + +*/ + + METHOD rid() { + INTVAL runloop_id; + GET_ATTR_runloop_id(INTERP, SELF, runloop_id); + RETURN(INTVAL runloop_id); + } + +/* + =item C Experimental: return callers PMC or PMCNULL if none. Index: src/call/ops.c =================================================================== --- src/call/ops.c (revision 46609) +++ src/call/ops.c (working copy) @@ -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 */