# 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