Author: jonathan Date: Fri Jan 16 09:33:50 2009 New Revision: 35636 Modified: trunk/include/parrot/sub.h trunk/src/pic_jit.c trunk/src/sub.c trunk/src/thread.c
Log: [core] PMC_sub could not check that we actually had something that was a sub underneath, nor did it handle the case where the Sub PMC had been subclassed by a high level class. Lots of code wanted a Parrot_Sub to be handed back by this, and not getting one could lead to segfaults. So this patch plugs those, and also makes it OK to subclass Sub in a high level class and use those subclasses with, e.g. capture_lex and elsewhere. The couple of other seemingly unreated changes in this patch are a result of needing to have an interp variable around to use PMC_sub now. All core tests pass. Modified: trunk/include/parrot/sub.h ============================================================================== --- trunk/include/parrot/sub.h (original) +++ trunk/include/parrot/sub.h Fri Jan 16 09:33:50 2009 @@ -171,7 +171,12 @@ struct Parrot_Context *outer_ctx; /* outer context, if a closure */ } Parrot_sub; -#define PMC_sub(pmc) ((Parrot_sub *)PMC_struct_val(pmc)) +#define PMC_sub(pmc) (pmc->vtable->base_type == enum_class_Sub || \ + pmc->vtable->base_type == enum_class_Coroutine || \ + pmc->vtable->base_type == enum_class_Eval || \ + pmc->vtable->base_type == enum_class_Closure ? \ + (Parrot_sub *)PMC_struct_val(pmc) : \ + Parrot_get_sub_pmc_from_subclass(interp, pmc)) /* the first entries must match Parrot_sub, so we can cast * these two to the other type @@ -272,6 +277,11 @@ PARROT_EXPORT PARROT_CANNOT_RETURN_NULL +Parrot_sub * Parrot_get_sub_pmc_from_subclass(PARROT_INTERP, PMC *subclass) + __attribute__nonnull__(1); + +PARROT_EXPORT +PARROT_CANNOT_RETURN_NULL PARROT_WARN_UNUSED_RESULT PMC* parrot_new_closure(PARROT_INTERP, ARGIN(PMC *sub_pmc)) __attribute__nonnull__(1) @@ -352,6 +362,9 @@ || PARROT_ASSERT_ARG(ctx) #define ASSERT_ARGS_Parrot_full_sub_name __attribute__unused__ int _ASSERT_ARGS_CHECK = \ PARROT_ASSERT_ARG(interp) +#define ASSERT_ARGS_Parrot_get_sub_pmc_from_subclass \ + __attribute__unused__ int _ASSERT_ARGS_CHECK = \ + PARROT_ASSERT_ARG(interp) #define ASSERT_ARGS_parrot_new_closure __attribute__unused__ int _ASSERT_ARGS_CHECK = \ PARROT_ASSERT_ARG(interp) \ || PARROT_ASSERT_ARG(sub_pmc) Modified: trunk/src/pic_jit.c ============================================================================== --- trunk/src/pic_jit.c (original) +++ trunk/src/pic_jit.c Fri Jan 16 09:33:50 2009 @@ -49,9 +49,12 @@ __attribute__nonnull__(3); PARROT_WARN_UNUSED_RESULT -static int call_is_safe(ARGIN(const PMC *sub), ARGMOD(opcode_t **set_args)) +static int call_is_safe(PARROT_INTERP, + ARGIN(const PMC *sub), + ARGMOD(opcode_t **set_args)) __attribute__nonnull__(1) __attribute__nonnull__(2) + __attribute__nonnull__(3) FUNC_MODIFIES(*set_args); PARROT_WARN_UNUSED_RESULT @@ -97,7 +100,8 @@ || PARROT_ASSERT_ARG(seg) \ || PARROT_ASSERT_ARG(start) #define ASSERT_ARGS_call_is_safe __attribute__unused__ int _ASSERT_ARGS_CHECK = \ - PARROT_ASSERT_ARG(sub) \ + PARROT_ASSERT_ARG(interp) \ + || PARROT_ASSERT_ARG(sub) \ || PARROT_ASSERT_ARG(set_args) #define ASSERT_ARGS_jit_can_compile_sub __attribute__unused__ int _ASSERT_ARGS_CHECK = \ PARROT_ASSERT_ARG(interp) \ @@ -328,7 +332,7 @@ PARROT_WARN_UNUSED_RESULT static int -call_is_safe(ARGIN(const PMC *sub), ARGMOD(opcode_t **set_args)) +call_is_safe(PARROT_INTERP, ARGIN(const PMC *sub), ARGMOD(opcode_t **set_args)) { ASSERT_ARGS(call_is_safe) PMC *called, *sig_results; @@ -407,7 +411,7 @@ break; case PARROT_OP_set_args_pc: /* verify call, return address after the call */ - if (!call_is_safe(sub, &pc)) + if (!call_is_safe(interp, sub, &pc)) return 0; *flags |= JIT_CODE_RECURSIVE; continue; Modified: trunk/src/sub.c ============================================================================== --- trunk/src/sub.c (original) +++ trunk/src/sub.c Fri Jan 16 09:33:50 2009 @@ -570,7 +570,7 @@ ASSERT_ARGS(Parrot_capture_lex) Parrot_Context * const ctx = CONTEXT(interp); Parrot_sub * const current_sub = PMC_sub(ctx->current_sub); - Parrot_sub * const sub = PMC_sub(sub_pmc); + Parrot_sub *sub; Parrot_Context *old; /* MultiSub gets special treatment */ @@ -592,6 +592,7 @@ } /* the sub_pmc has to have an outer_sub that is the caller */ + sub = PMC_sub(sub_pmc); if (PMC_IS_NULL(sub->outer_sub)) return; @@ -704,6 +705,43 @@ interp->ctx.bp_ps = to_ctx->bp_ps; } + +/* + +=item C<Parrot_sub * Parrot_get_sub_pmc_from_subclass> + +Gets a Parrot_sub structure from something that isn't a Sub PMC, but rather a +subclass. + +=cut + +*/ + +PARROT_EXPORT +PARROT_CANNOT_RETURN_NULL +Parrot_sub * +Parrot_get_sub_pmc_from_subclass(PARROT_INTERP, ARGIN(PMC *subclass)) { + ASSERT_ARGS(Parrot_get_sub_pmc_from_subclass) + PMC *key, *sub_pmc; + + /* Ensure we really do have a subclass of sub. */ + if (VTABLE_isa(interp, subclass, CONST_STRING(interp, "Sub"))) { + /* If it's actually a PMC still, probably does the same structure + * underneath. */ + if (!PObj_is_object_TEST(subclass)) + return (Parrot_sub *)PMC_struct_val(subclass); + + /* Get the Sub PMC itself. */ + key = pmc_new(interp, enum_class_String); + VTABLE_set_string_native(interp, key, CONST_STRING(interp, "Sub")); + sub_pmc = VTABLE_get_attr_keyed(interp, subclass, key, CONST_STRING(interp, "proxy")); + if (sub_pmc->vtable->base_type == enum_class_Sub) + return (Parrot_sub *)PMC_struct_val(sub_pmc); + } + Parrot_ex_throw_from_op_args(interp, NULL, EXCEPTION_INVALID_OPERATION, + "Attempting to do sub operation on non-Sub."); +} + /* =back Modified: trunk/src/thread.c ============================================================================== --- trunk/src/thread.c (original) +++ trunk/src/thread.c Fri Jan 16 09:33:50 2009 @@ -68,7 +68,7 @@ static void pt_gc_wakeup_check(PARROT_INTERP) __attribute__nonnull__(1); -static void pt_ns_clone( +static void pt_ns_clone(PARROT_INTERP, ARGOUT(Parrot_Interp d), ARGOUT(PMC *dest_ns), ARGIN(Parrot_Interp s), @@ -77,6 +77,7 @@ __attribute__nonnull__(2) __attribute__nonnull__(3) __attribute__nonnull__(4) + __attribute__nonnull__(5) FUNC_MODIFIES(d) FUNC_MODIFIES(*dest_ns); @@ -123,7 +124,8 @@ #define ASSERT_ARGS_pt_gc_wakeup_check __attribute__unused__ int _ASSERT_ARGS_CHECK = \ PARROT_ASSERT_ARG(interp) #define ASSERT_ARGS_pt_ns_clone __attribute__unused__ int _ASSERT_ARGS_CHECK = \ - PARROT_ASSERT_ARG(d) \ + PARROT_ASSERT_ARG(interp) \ + || PARROT_ASSERT_ARG(d) \ || PARROT_ASSERT_ARG(dest_ns) \ || PARROT_ASSERT_ARG(s) \ || PARROT_ASSERT_ARG(source_ns) @@ -593,7 +595,7 @@ */ static void -pt_ns_clone(ARGOUT(Parrot_Interp d), ARGOUT(PMC *dest_ns), +pt_ns_clone(PARROT_INTERP, ARGOUT(Parrot_Interp d), ARGOUT(PMC *dest_ns), ARGIN(Parrot_Interp s), ARGIN(PMC *source_ns)) { ASSERT_ARGS(pt_ns_clone) @@ -613,7 +615,7 @@ sub_ns = pmc_new(d, enum_class_NameSpace); VTABLE_set_pmc_keyed_str(d, dest_ns, key, sub_ns); } - pt_ns_clone(d, sub_ns, s, val); + pt_ns_clone(s, d, sub_ns, s, val); } else { PMC * const dval = VTABLE_get_pmc_keyed_str(d, dest_ns, key); @@ -647,7 +649,7 @@ { ASSERT_ARGS(pt_clone_globals) Parrot_block_GC_mark(d); - pt_ns_clone(d, d->root_namespace, s, s->root_namespace); + pt_ns_clone(s, d, d->root_namespace, s, s->root_namespace); Parrot_unblock_GC_mark(d); }