# 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 *);