# 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

Reply via email to