Index: src/exceptions.c =================================================================== --- src/exceptions.c (revision 39934) +++ src/exceptions.c (working copy) @@ -1,5 +1,5 @@ /* -Copyright (C) 2001-2008, Parrot Foundation. +Copyright (C) 2001-2009, Parrot Foundation. $Id$ =head1 NAME @@ -343,6 +343,7 @@ Parrot_runloop *return_point = interp->current_runloop; RunProfile * const profile = interp->profile; + opcode_t *address; PMC * const handler = Parrot_cx_find_handler_local(interp, exception); @@ -384,12 +385,13 @@ } /* Run the handler. */ - Parrot_runops_fromc_args(interp, handler, "vP", exception); - - /* After handling a C exception, you don't want to resume at the point - * where the C exception was thrown. You want to resume the next outer - * runloop. */ - longjmp(return_point->resume, 1); + address = VTABLE_invoke(interp, handler, NULL); + if (PMC_cont(handler)->current_results) + address = pass_exception_args(interp, "P", address, + CONTEXT(interp), exception); + PARROT_ASSERT(return_point->handler_start == NULL); + return_point->handler_start = address; + longjmp(return_point->resume, 2); } /* Index: src/call/ops.c =================================================================== --- src/call/ops.c (revision 39934) +++ src/call/ops.c (working copy) @@ -88,24 +88,37 @@ #endif { new_runloop_jump_point(interp); - if (setjmp(interp->current_runloop->resume)) { - /* an exception was handled */ - if (STACKED_EXCEPTIONS) - free_runloop_jump_point(interp); + reenter: + interp->current_runloop->handler_start = NULL; + switch (setjmp(interp->current_runloop->resume)) { + case 1: + /* an exception was handled */ + if (STACKED_EXCEPTIONS) + free_runloop_jump_point(interp); - interp->current_runloop_level = our_runloop_level - 1; - interp->current_runloop_id = old_runloop_id; + interp->current_runloop_level = our_runloop_level - 1; + interp->current_runloop_id = old_runloop_id; #if RUNLOOP_TRACE - fprintf(stderr, "[handled exception; back to loop %d, level %d]\n", - interp->current_runloop_id, interp->current_runloop_level); + fprintf(stderr, "[handled exception; back to loop %d, level %d]\n", + interp->current_runloop_id, interp->current_runloop_level); #endif - return; + return; + case 2: + /* Reenter the runloop from a exception thrown from C + * with a pir handler */ + PARROT_ASSERT(interp->current_runloop->handler_start); + offset = interp->current_runloop->handler_start - interp->code->base.data; + /* Prevent incorrect reuse */ + goto reenter; + default: + break; } } runops_int(interp, offset); + interp->current_runloop->handler_start = NULL; /* Remove the current runloop marker (put it on the free list). */ if (STACKED_EXCEPTIONS || interp->current_runloop) free_runloop_jump_point(interp); Index: include/parrot/interpreter.h =================================================================== --- include/parrot/interpreter.h (revision 39934) +++ include/parrot/interpreter.h (working copy) @@ -1,5 +1,5 @@ /* interpreter.h - * Copyright (C) 2001-2007, Parrot Foundation. + * Copyright (C) 2001-2009, Parrot Foundation. * SVN Info * $Id$ * Overview: @@ -290,8 +290,10 @@ * runloop ID, so it still needs to be a separate stack for a while longer. */ typedef struct parrot_runloop_t { - Parrot_jump_buff resume; /* jmp_buf */ - struct parrot_runloop_t *prev; /* interpreter's runloop jump buffer stack */ + Parrot_jump_buff resume; /* jmp_buf */ + struct parrot_runloop_t *prev; /* interpreter's runloop + * jump buffer stack */ + opcode_t *handler_start; /* Used in exception handling */ } parrot_runloop_t; typedef parrot_runloop_t Parrot_runloop;