# New Ticket Created by Stephen Weeks # Please include the string: [perl #57610] # in the subject line of all future correspondence about this issue. # <URL: http://rt.perl.org/rt3/Ticket/Display.html?id=57610 >
pdd23: Exception handlers can resume execution immediately after the "throw" opcode by invoking the resume continuation which is stored in the exception object. That continuation must be invoked with no parameters; in other words, "throw" never returns a value. Exception.pmc has the following attributes: ATTR INTVAL id; /* The task ID in the scheduler. */ ATTR FLOATVAL birthtime; /* The creation time stamp of the exception. */ ATTR STRING *message; /* The exception message. */ ATTR PMC *payload; /* The payload for the exception. */ ATTR INTVAL severity; /* The severity of the exception. */ ATTR INTVAL type; /* The type of the exception. */ ATTR INTVAL exit_code; /* The exit code of the exception. */ ATTR PMC *stacktrace; /* The stacktrace of an exception. */ ATTR INTVAL handled; /* Whether the exception has been handled. */ ATTR PMC *handler_iter; /* An iterator of handlers (for rethrow). */ ATTR Parrot_Context *handler_ctx; /* A stored context for handler iterator. */ None of these is a continuation. The throw opcode passes the address of the next opcode to Parrot_ex_throw_from_op, but Petfo only uses it in: address = VTABLE_invoke(interp, handler, dest); and the ExceptionHandler PMC's invoke() does not use that parameter at all. This first draft of a patch adds an attribute to the exception pmc to hold a return continuation, creates a retcontinuation pmc in the throw opcode and assigns it to that attribute, and patches new_ret_continuation to initialize the new continuation's from_ctx attribute in the same way new_continuation does. This last item is there to fix a segfault. I don't understand parrot's continuations well enough yet to have any idea why they were different, so I just guessed. I don't know if it's wrong, but it doesn't seem to fail any extra tests. Added a simple test case.
>From 21bc85c3ae1d749187b250bd898028d63a92891f Mon Sep 17 00:00:00 2001 From: Stephen Weeks <[EMAIL PROTECTED]> Date: Tue, 5 Aug 2008 04:55:30 -0600 Subject: [PATCH] Add a return continuation attribute to the Exception pmc and fill it in the throw opcode. --- src/ops/core.ops | 4 +++- src/pmc/exception.pmc | 10 ++++++++++ src/sub.c | 2 +- t/op/exceptions.t | 25 ++++++++++++++++++++++++- 4 files changed, 38 insertions(+), 3 deletions(-) diff --git a/src/ops/core.ops b/src/ops/core.ops index 25f8775..da821f3 100644 --- a/src/ops/core.ops +++ b/src/ops/core.ops @@ -816,7 +816,9 @@ inline op pop_eh() { inline op throw(invar PMC) :flow { opcode_t * const ret = expr NEXT(); - opcode_t * const dest = Parrot_ex_throw_from_op(interp, $1, ret); + Parrot_cont * resume = new_ret_continuation_pmc(interp,ret); + VTABLE_set_attr_str(interp,$1,string_from_literal(interp,"retcont"),resume); + opcode_t * const dest = Parrot_ex_throw_from_op(interp, $1, resume); goto ADDRESS(dest); } diff --git a/src/pmc/exception.pmc b/src/pmc/exception.pmc index 15c7056..2a09882 100644 --- a/src/pmc/exception.pmc +++ b/src/pmc/exception.pmc @@ -57,6 +57,7 @@ pmclass Exception { ATTR FLOATVAL birthtime; /* The creation time stamp of the exception. */ ATTR STRING *message; /* The exception message. */ ATTR PMC *payload; /* The payload for the exception. */ + ATTR PMC *retcont; /* The return continuation for the exception. */ ATTR INTVAL severity; /* The severity of the exception. */ ATTR INTVAL type; /* The type of the exception. */ ATTR INTVAL exit_code; /* The exit code of the exception. */ @@ -93,6 +94,7 @@ Initializes the exception with default values. core_struct->handled = 0; core_struct->message = CONST_STRING(interp, ""); core_struct->payload = PMCNULL; + core_struct->retcont = PMCNULL; core_struct->stacktrace = PMCNULL; core_struct->handler_iter = PMCNULL; } @@ -113,6 +115,8 @@ Mark any active exception data as live. pobject_lives(interp, (PObj *)core_struct->message); if (core_struct->payload) pobject_lives(interp, (PObj *)core_struct->payload); + if (core_struct->retcont) + pobject_lives(interp, (PObj *)core_struct->retcont); if (core_struct->stacktrace) pobject_lives(interp, (PObj *)core_struct->stacktrace); if (core_struct->handler_iter) @@ -530,6 +534,9 @@ Retrieve an attribute value for the exception object. else if (string_equal(INTERP, name, CONST_STRING(INTERP, "payload")) == 0) { GET_ATTR_payload(interp, SELF, value); } + else if (string_equal(INTERP, name, CONST_STRING(INTERP, "retcont")) == 0) { + GET_ATTR_retcont(interp, SELF, value); + } else if (string_equal(INTERP, name, CONST_STRING(INTERP, "stacktrace")) == 0) { GET_ATTR_stacktrace(interp, SELF, value); } @@ -579,6 +586,9 @@ Set an attribute value for the exception object. else if (string_equal(INTERP, name, CONST_STRING(INTERP, "payload")) == 0) { SET_ATTR_payload(interp, SELF, value); } + else if (string_equal(INTERP, name, CONST_STRING(INTERP, "retcont")) == 0) { + SET_ATTR_retcont(interp, SELF, value); + } else if (string_equal(INTERP, name, CONST_STRING(INTERP, "stacktrace")) == 0) { SET_ATTR_stacktrace(interp, SELF, value); } diff --git a/src/sub.c b/src/sub.c index bcc7bdb..529ddc0 100644 --- a/src/sub.c +++ b/src/sub.c @@ -191,7 +191,7 @@ new_ret_continuation(PARROT_INTERP) Parrot_cont * const cc = mem_allocate_typed(Parrot_cont); cc->to_ctx = CONTEXT(interp); - cc->from_ctx = NULL; /* filled in during a call */ + cc->from_ctx = CONTEXT(interp); /* filled in during a call */ cc->dynamic_state = NULL; cc->runloop_id = 0; cc->seg = interp->code; diff --git a/t/op/exceptions.t b/t/op/exceptions.t index e49f647..1c4aa1f 100644 --- a/t/op/exceptions.t +++ b/t/op/exceptions.t @@ -6,7 +6,7 @@ use strict; use warnings; use lib qw( . lib ../lib ../../lib ); use Test::More; -use Parrot::Test tests => 29; +use Parrot::Test tests => 30; =head1 NAME @@ -608,6 +608,29 @@ Exception message: Class Foo already registered! after compile OUTPUT +pir_output_is( <<'CODE', <<'OUTPUT', "Resumable exceptions" ); +.sub main :main + push_eh _handler + new $P1, 'Exception' + say 'Before throwing' + throw $P1 + say 'After throwing' + end +_handler: + .local pmc e + .local string s + .local pmc c + .get_results (e, s) + say 'In the exception handler' + c = e['retcont'] + c() +.end +CODE +Before throwing +In the exception handler +After throwing +OUTPUT + # Local Variables: # mode: cperl # cperl-indent-level: 4 -- 1.5.5.1