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);
 }
 

Reply via email to