# New Ticket Created by  chromatic 
# Please include the string:  [perl #46481]
# in the subject line of all future correspondence about this issue. 
# <URL: http://rt.perl.org/rt3/Ticket/Display.html?id=46481 >


Here's a nifty little patch that adds a new runcore which runs a full GC cycle 
after each op.  As you might expect, it takes a bit longer than normal tests 
(so I don't really recommend it for running the shootouts), but it has the 
possibility of finding GC bugs very thoroughly.  Running it on t/pmc/*.t 
shows failures of the "Hey, there are a few segfaults here!" kind in:

t/pmc/delegate.t                 1   256     9    1  8
t/pmc/eval.t                     2   512    17    2  12-13
t/pmc/exporter.t                 8  2048    12    8  2-3 7-12
t/pmc/freeze.t                   2   512    25    2  24-25
t/pmc/io.t                       2   512    45    1  42
t/pmc/iterator.t                 3   768    44    3  29-31
t/pmc/mmd.t                      5  1280    44    5  8 10 29-30 32
t/pmc/objects.t                  2   512    80    2  17 65
t/pmc/pmcproxy.t                 1   256     9    1  9
t/pmc/resizablepmcarray.t        1   256    38    1  25
t/pmc/sub.t                      2   512    61    2  55-56
t/pmc/threads.t                  3   768    20    3  6 9 18

I used the -X flag because it wasn't taken, but I'm happy to rename it to a 
better alternative.

-- c
=== compilers/imcc/main.c
==================================================================
--- compilers/imcc/main.c	(revision 6364)
+++ compilers/imcc/main.c	(local)
@@ -214,6 +214,7 @@
     { 'O', 'O', OPTION_optional_FLAG, { "--optimize" } },
     { 'S', 'S', (OPTION_flags)0, { "--switched-core" } },
     { 'V', 'V', (OPTION_flags)0, { "--version" } },
+    { 'X', 'X', (OPTION_flags)0, { "--gc-core" } },
     { '\0', OPT_DESTROY_FLAG, (OPTION_flags)0,
                                  { "--leak-test", "--destroy-at-end" } },
     { '\0', OPT_GC_DEBUG, (OPTION_flags)0, { "--gc-debug" } },
@@ -367,6 +368,9 @@
                 if (!interp->output_file)
                     interp->output_file = "-";
                 break;
+            case 'X':
+                SET_CORE(PARROT_GC_CORE);
+                break;
 
             case 'O':
                 if (!opt.opt_arg) {
=== include/parrot/interpreter.h
==================================================================
--- include/parrot/interpreter.h	(revision 6364)
+++ include/parrot/interpreter.h	(local)
@@ -61,16 +61,17 @@
 
 /* &gen_from_enum(interpcores.pasm) */
 typedef enum {
-    PARROT_SLOW_CORE,                         /* slow bounds/trace/profile core */
-    PARROT_FUNCTION_CORE = PARROT_SLOW_CORE,
-    PARROT_FAST_CORE      = 0x01,             /* fast DO_OP core */
-    PARROT_SWITCH_CORE    = 0x02,             /*   P   = prederef   */
-    PARROT_CGP_CORE       = 0x06,             /*  CP                */
-    PARROT_CGOTO_CORE     = 0x04,             /*  C    = cgoto      */
-    PARROT_JIT_CORE       = 0x10,             /* J     = JIT        */
-    PARROT_CGP_JIT_CORE   = 0x16,             /* JCP                */
-    PARROT_SWITCH_JIT_CORE  = 0x12,           /* J P                */
-    PARROT_EXEC_CORE      = 0x20          /* TODO Parrot_exec_run variants */
+    PARROT_SLOW_CORE,                       /* slow bounds/trace/profile core */
+    PARROT_FUNCTION_CORE    = PARROT_SLOW_CORE,
+    PARROT_FAST_CORE        = 0x01,         /* fast DO_OP core */
+    PARROT_SWITCH_CORE      = 0x02,         /*   P   = prederef   */
+    PARROT_CGP_CORE         = 0x06,         /*  CP                */
+    PARROT_CGOTO_CORE       = 0x04,         /*  C    = cgoto      */
+    PARROT_JIT_CORE         = 0x10,         /* J     = JIT        */
+    PARROT_CGP_JIT_CORE     = 0x16,         /* JCP                */
+    PARROT_SWITCH_JIT_CORE  = 0x12,         /* J P                */
+    PARROT_EXEC_CORE        = 0x20,         /* TODO Parrot_exec_run variants */
+    PARROT_GC_CORE          = 0x40          /* run GC between each op */
 } Parrot_Run_core_t;
 /* &end_gen */
 
=== src/interpreter.c
==================================================================
--- src/interpreter.c	(revision 6364)
+++ src/interpreter.c	(local)
@@ -369,10 +369,11 @@
                 init_func = PARROT_CORE_CG_OPLIB_INIT;
                 break;
 #endif
-            case PARROT_EXEC_CORE:      /* normal func core */
+            case PARROT_EXEC_CORE:     /* normal func core */
             case PARROT_JIT_CORE:      /* normal func core */
-            case PARROT_SLOW_CORE:      /* normal func core */
-            case PARROT_FAST_CORE:      /* normal func core */
+            case PARROT_SLOW_CORE:     /* normal func core */
+            case PARROT_FAST_CORE:     /* normal func core */
+            case PARROT_GC_CORE:       /* normal func core */
                 init_func = PARROT_CORE_OPLIB_INIT;
                 break;
             default:
@@ -844,6 +845,9 @@
 #endif
                 core = runops_exec;
                 break;
+            case PARROT_GC_CORE:
+                core = runops_gc_core;
+                break;
             default:
                 real_exception(interp, NULL, UNIMPLEMENTED,
                         "ambigious runcore switch used");
=== src/runops_cores.c
==================================================================
--- src/runops_cores.c	(revision 6364)
+++ src/runops_cores.c	(local)
@@ -200,6 +200,37 @@
 
         DO_OP(pc, interp);
     }
+    return pc;
+}
+
+/*
+
+=item C<runops_gc_core>
+
+Runs the Parrot operations starting at C<pc> until there are no more
+operations, and performs a full GC run after each op.  This is very slow, but
+it's also a very quick way to find GC problems.
+
+=cut
+
+*/
+
+PARROT_WARN_UNUSED_RESULT
+PARROT_CAN_RETURN_NULL
+opcode_t *
+runops_gc_core(PARROT_INTERP, NOTNULL(opcode_t *pc))
+{
+    while (pc) {
+        if (pc < code_start || pc >= code_end) {
+            real_exception(interp, NULL, 1,
+                    "attempt to access code outside of current code segment");
+        }
+        CONTEXT(interp->ctx)->current_pc = pc;
+
+        DO_OP(pc, interp);
+        Parrot_do_dod_run(interp, 0);
+    }
+
 #undef code_start
 #undef code_end
     return pc;
@@ -254,8 +285,12 @@
     return pc;
 }
 
+/*
 
+=back
 
+*/
+
 /*
  * Local variables:
  *   c-file-style: "parrot"
=== src/runops_cores.h
==================================================================
--- src/runops_cores.h	(revision 6364)
+++ src/runops_cores.h	(local)
@@ -42,6 +42,12 @@
         __attribute__nonnull__(1)
         __attribute__nonnull__(2);
 
+PARROT_WARN_UNUSED_RESULT
+PARROT_CAN_RETURN_NULL
+opcode_t * runops_gc_core(PARROT_INTERP, NOTNULL(opcode_t *pc))
+        __attribute__nonnull__(1)
+        __attribute__nonnull__(2);
+
 /* HEADERIZER END: src/runops_cores.c */
 
 opcode_t *runops_fast_core(PARROT_INTERP, opcode_t *);

Reply via email to