Skip to content

Commit

Permalink
Merge branch 'exceptions_subclass'
Browse files Browse the repository at this point in the history
  • Loading branch information
Whiteknight committed Jan 20, 2011
2 parents 947dcf8 + ed2c343 commit 07fbbcf
Show file tree
Hide file tree
Showing 8 changed files with 98 additions and 20 deletions.
3 changes: 2 additions & 1 deletion src/exceptions.c
Expand Up @@ -75,7 +75,8 @@ Parrot_ex_build_exception(PARROT_INTERP, INTVAL severity,
long error, ARGIN_NULLOK(STRING *msg))
{
ASSERT_ARGS(Parrot_ex_build_exception)
PMC * const exception = Parrot_pmc_new(interp, enum_class_Exception);
const int exception_type_id = Parrot_hll_get_ctx_HLL_type(interp, enum_class_Exception);
PMC * const exception = Parrot_pmc_new(interp, exception_type_id);

VTABLE_set_integer_keyed_str(interp, exception, CONST_STRING(interp, "severity"), severity);
VTABLE_set_integer_keyed_str(interp, exception, CONST_STRING(interp, "type"), error);
Expand Down
16 changes: 11 additions & 5 deletions src/ops/core.ops
Expand Up @@ -737,10 +737,11 @@ inline op throw(invar PMC) :flow {
opcode_t *dest;
opcode_t * const ret = expr NEXT();
PMC * const resume = pmc_new(interp, enum_class_Continuation);
STRING * const exception_str = CONST_STRING(interp, "Exception");

VTABLE_set_pointer(interp, resume, ret);

if (PMC_IS_NULL(except) || except->vtable->base_type != enum_class_Exception)
if (PMC_IS_NULL(except) || !VTABLE_does(interp, except, exception_str))
except = Parrot_ex_build_exception(interp, EXCEPT_fatal,
EXCEPTION_UNIMPLEMENTED,
Parrot_str_new_constant(interp, "Not a throwable object"));
Expand All @@ -753,7 +754,9 @@ inline op throw(invar PMC) :flow {
inline op throw(invar PMC, invar PMC) :flow {
opcode_t * dest;
PMC * except = $1;
if (PMC_IS_NULL(except) || except->vtable->base_type != enum_class_Exception)
STRING * const exception_str = CONST_STRING(interp, "Exception");

if (PMC_IS_NULL(except) || !VTABLE_does(interp, except, exception_str))
except = Parrot_ex_build_exception(interp, EXCEPT_fatal,
EXCEPTION_UNIMPLEMENTED,
Parrot_str_new_constant(interp, "Not a throwable object"));
Expand All @@ -764,15 +767,18 @@ inline op throw(invar PMC, invar PMC) :flow {

inline op rethrow(invar PMC) :flow {
opcode_t * dest;
if (PMC_IS_NULL($1) || $1->vtable->base_type != enum_class_Exception) {
PMC * except = $1;
STRING * const exception_str = CONST_STRING(interp, "Exception");

if (PMC_IS_NULL(except) || !VTABLE_does(interp, except, exception_str)) {
opcode_t * const ret = expr NEXT();
PMC * const except = Parrot_ex_build_exception(interp, EXCEPT_fatal,
except = Parrot_ex_build_exception(interp, EXCEPT_fatal,
EXCEPTION_UNIMPLEMENTED,
Parrot_str_new_constant(interp, "Not a throwable object"));
dest = Parrot_ex_throw_from_op(interp, except, ret);
goto ADDRESS(dest);
}
dest = Parrot_ex_rethrow_from_op(interp, $1);
dest = Parrot_ex_rethrow_from_op(interp, except);
goto ADDRESS(dest);
}

Expand Down
18 changes: 12 additions & 6 deletions src/ops/core_ops.c
Expand Up @@ -15552,10 +15552,11 @@ Parrot_throw_p(opcode_t *cur_opcode, PARROT_INTERP) {
opcode_t *dest;
opcode_t * const ret = cur_opcode + 2;
PMC * const resume = pmc_new(interp, enum_class_Continuation);
STRING * const exception_str = Parrot_str_new_constant(interp, "Exception");

VTABLE_set_pointer(interp, resume, ret);

if (PMC_IS_NULL(except) || except->vtable->base_type != enum_class_Exception)
if (PMC_IS_NULL(except) || !VTABLE_does(interp, except, exception_str))
except = Parrot_ex_build_exception(interp, EXCEPT_fatal,
EXCEPTION_UNIMPLEMENTED,
Parrot_str_new_constant(interp, "Not a throwable object"));
Expand All @@ -15569,7 +15570,9 @@ Parrot_throw_p_p(opcode_t *cur_opcode, PARROT_INTERP) {
const Parrot_Context * const CUR_CTX = Parrot_pcc_get_context_struct(interp, interp->ctx);
opcode_t * dest;
PMC * except = PREG(1);
if (PMC_IS_NULL(except) || except->vtable->base_type != enum_class_Exception)
STRING * const exception_str = Parrot_str_new_constant(interp, "Exception");

if (PMC_IS_NULL(except) || !VTABLE_does(interp, except, exception_str))
except = Parrot_ex_build_exception(interp, EXCEPT_fatal,
EXCEPTION_UNIMPLEMENTED,
Parrot_str_new_constant(interp, "Not a throwable object"));
Expand All @@ -15581,14 +15584,17 @@ opcode_t *
Parrot_rethrow_p(opcode_t *cur_opcode, PARROT_INTERP) {
const Parrot_Context * const CUR_CTX = Parrot_pcc_get_context_struct(interp, interp->ctx);
opcode_t * dest;
if (PMC_IS_NULL(PREG(1)) || PREG(1)->vtable->base_type != enum_class_Exception) {
PMC * except = PREG(1);
STRING * const exception_str = Parrot_str_new_constant(interp, "Exception");

if (PMC_IS_NULL(except) || !VTABLE_does(interp, except, exception_str)) {
opcode_t * const ret = cur_opcode + 2;
PMC * const except = Parrot_ex_build_exception(interp, EXCEPT_fatal,
except = Parrot_ex_build_exception(interp, EXCEPT_fatal,
EXCEPTION_UNIMPLEMENTED,
Parrot_str_new_constant(interp, "Not a throwable object"));
dest = Parrot_ex_throw_from_op(interp, except, ret);return (opcode_t *)dest;
}
dest = Parrot_ex_rethrow_from_op(interp, PREG(1));return (opcode_t *)dest;
dest = Parrot_ex_rethrow_from_op(interp, except);return (opcode_t *)dest;
}

opcode_t *
Expand Down Expand Up @@ -25832,7 +25838,7 @@ op_lib_t core_op_lib = {
1071, /* op_count */
core_op_info_table, /* op_info_table */
core_op_func_table, /* op_func_table */
get_op /* op_code() */
get_op /* op_code() */
};

/*
Expand Down
2 changes: 1 addition & 1 deletion src/pmc/exception.pmc
Expand Up @@ -84,7 +84,7 @@ static AttrEnum getAttrEnum(PARROT_INTERP, ARGIN(const STRING *name))
/* HEADERIZER END: static */


pmclass Exception auto_attrs {
pmclass Exception provides Exception auto_attrs {

ATTR INTVAL id; /* The task ID in the scheduler. */
ATTR FLOATVAL birthtime; /* The creation time stamp of the exception. */
Expand Down
2 changes: 2 additions & 0 deletions src/pmc/exceptionhandler.pmc
Expand Up @@ -181,6 +181,8 @@ Report whether the exception handler can handle a particular type of exception.

INTVAL severity = VTABLE_get_integer_keyed_str(INTERP, exception, sev);

/* We handle Exception and anything that claims to implement that role
here. Include the base_type check as a sort of optimization */
if (exception->vtable->base_type == enum_class_Exception
|| VTABLE_isa(INTERP, exception, ex_str)) {
PMC *handled_types;
Expand Down
6 changes: 3 additions & 3 deletions src/pmc/scheduler.pmc
Expand Up @@ -139,7 +139,7 @@ current maximum, and a birthtime of the current time.

SCHEDULER_cache_valid_CLEAR(SELF);

if (task->vtable->base_type != enum_class_Exception)
if (!VTABLE_does(interp, task, CONST_STRING(interp, "Exception")))
Parrot_cx_runloop_wake(core_struct->INTERP, SELF);
}

Expand Down Expand Up @@ -455,7 +455,7 @@ PMCNULL.

/* Exceptions store the handler iterator for rethrow, other kinds of
* tasks don't (though they could). */
if (task->vtable->base_type == enum_class_Exception
if (VTABLE_does(interp, task, CONST_STRING(interp, "Exception"))
&& VTABLE_get_integer_keyed_str(INTERP, task, handled_str) == -1) {
iter = VTABLE_get_attr_str(INTERP, task, iter_str);
}
Expand All @@ -476,7 +476,7 @@ PMCNULL.
if (!PMC_IS_NULL(handler)) {
(const INTVAL valid_handler) = PCCINVOKE(INTERP, handler, "can_handle", PMC *task);
if (valid_handler) {
if (task->vtable->base_type == enum_class_Exception)
if (!VTABLE_does(interp, task, CONST_STRING(interp, "Exception")))
VTABLE_set_integer_native(INTERP, handler, 1);
RETURN(PMC *handler);
}
Expand Down
8 changes: 5 additions & 3 deletions src/scheduler.c
Expand Up @@ -861,6 +861,8 @@ Parrot_cx_find_handler_local(PARROT_INTERP, ARGIN(PMC *task))
PMC *iter = PMCNULL;
STRING * const handled_str = CONST_STRING(interp, "handled");
STRING * const handler_iter_str = CONST_STRING(interp, "handler_iter");
STRING * const exception_str = CONST_STRING(interp, "Exception");
const Parrot_Int is_exception = VTABLE_does(interp, task, exception_str);

if (already_doing) {
Parrot_io_eprintf(interp,
Expand All @@ -884,8 +886,8 @@ Parrot_cx_find_handler_local(PARROT_INTERP, ARGIN(PMC *task))

/* Exceptions store the handler iterator for rethrow, other kinds of
* tasks don't (though they could). */
if (task->vtable->base_type == enum_class_Exception
&& VTABLE_get_integer_keyed_str(interp, task, handled_str) == -1) {
if (is_exception &&
VTABLE_get_integer_keyed_str(interp, task, handled_str) == -1) {
iter = VTABLE_get_attr_str(interp, task, handler_iter_str);
context = (PMC *)VTABLE_get_pointer(interp, task);
}
Expand All @@ -910,7 +912,7 @@ Parrot_cx_find_handler_local(PARROT_INTERP, ARGIN(PMC *task))
"P->I", task, &valid_handler);

if (valid_handler) {
if (task->vtable->base_type == enum_class_Exception) {
if (is_exception) {
/* Store iterator and context for a later rethrow. */
VTABLE_set_attr_str(interp, task, handler_iter_str, iter);
VTABLE_set_pointer(interp, task, context);
Expand Down
63 changes: 62 additions & 1 deletion t/pmc/exception.t
Expand Up @@ -19,7 +19,7 @@ Tests C<Exception> and C<ExceptionHandler> PMCs.

.sub main :main
.include 'test_more.pir'
plan(47)
plan(53)
test_bool()
test_int()
test_new_int()
Expand All @@ -40,6 +40,8 @@ Tests C<Exception> and C<ExceptionHandler> PMCs.
test_throw_serialized()
test_backtrace()
test_annotations()
test_subclass_throw()
test_subclass_finalize()
.end

.sub test_bool
Expand Down Expand Up @@ -471,6 +473,65 @@ _handler:
is($I0, 0, 'annotations from unthrow Exception are empty')
.end

.sub test_subclass_throw
$P1 = get_class ["Exception"]
$P2 = subclass $P1, "MyException"
$P3 = new $P2
$S0 = typeof $P3
is ($S0, "MyException", "can create a subclass")
$S0 = $P3
is ($S0, "MyException", "really is a subclass, with :vtable override")

push_eh my_handler
throw $P3
pop_eh
ok(0, "Could not throw MyException")
.return()
my_handler:
.get_results($P4)
pop_eh
$S0 = typeof $P4
is ($S0, "MyException", "received a MyException object")
$S0 = $P4
is ($S0, "MyException", "really is a subclass, with :vtable override")
.return()
.end

.sub test_subclass_finalize
$P0 = newclass "MyBuggyObject"
$P3 = new $P0
push_eh my_handler
$S0 = $P3
pop_eh
ok(0, "MyBuggyObject not as buggy as advertised")
.return()
my_handler:
.get_results($P4)
$S0 = typeof $P4
is ($S0, "MyException", "received a MyException object")
$S0 = $P4
is ($S0, "MyException", "really is a subclass, with :vtable override")
finalize $P4
.return()
.end

.namespace ["MyException"]

.sub get_string :vtable("get_string") :method
.return("MyException")
.end

.namespace ["MyBuggyObject"]

.sub get_string :vtable("get_string") :method
$P0 = new ["MyException"]
say "throwing"
throw $P0
say "this didn't work!"
ok(0, "Oops! We shouldn't ever end up here unless finalize fails")
exit 1
.end

# Local Variables:
# mode: pir
# fill-column: 100
Expand Down

0 comments on commit 07fbbcf

Please sign in to comment.