Okay, after some major changes, here's the second revision of my patch. This one is fully functional.
On my system, it creates over a 10x speedup for lazy DOD runs! (I'll post the benchmark program if someone wants; it's pretty long) Luke Index: core.ops =================================================================== RCS file: /cvs/public/parrot/core.ops,v retrieving revision 1.324 diff -u -r1.324 core.ops --- core.ops 29 Aug 2003 11:30:17 -0000 1.324 +++ core.ops 10 Sep 2003 04:37:06 -0000 @@ -837,8 +837,11 @@ =cut op sweep(inconst INT) { - if ($1 || interpreter->has_early_DOD_PMCs) + if ($1) Parrot_do_dod_run(interpreter, 0); + else + if (interpreter->num_early_DOD_PMCs) + Parrot_do_dod_run(interpreter, DOD_lazy_FLAG); goto NEXT(); } @@ -906,8 +909,8 @@ op needs_destroy(in PMC) { PObj_needs_early_DOD_SET($1); - interpreter->has_early_DOD_PMCs = 1; - goto NEXT(); + interpreter->num_early_DOD_PMCs++; + goto NEXT(); } =back Index: dod.c =================================================================== RCS file: /cvs/public/parrot/dod.c,v retrieving revision 1.70 diff -u -r1.70 dod.c --- dod.c 28 Aug 2003 16:56:15 -0000 1.70 +++ dod.c 10 Sep 2003 04:37:06 -0000 @@ -31,7 +31,7 @@ #endif static size_t find_common_mask(size_t val1, size_t val2); -static void trace_children(struct Parrot_Interp *interpreter, PMC *current); +static int trace_children(struct Parrot_Interp *interpreter, PMC *current); #if ARENA_DOD_FLAGS @@ -43,23 +43,49 @@ size_t ns = n >> ARENA_FLAG_SHIFT; UINTVAL nm = (n & ARENA_FLAG_MASK) << 2; UINTVAL *dod_flags = arena->dod_flags + ns; - if (*dod_flags & ((PObj_on_free_list_FLAG | PObj_live_FLAG) << nm)) + + if (*dod_flags & PObj_on_free_list_FLAG << nm) + return; + if (PObj_high_priority_DOD_TEST(obj) && interpreter->dod_trace_ptr) + /* set obj's parent to high priority */ + PObj_high_priority_DOD_SET(interpreter->dod_trace_ptr); + if (*dod_flags & PObj_live_FLAG << nm) return; ++arena->live_objects; *dod_flags |= PObj_live_FLAG << nm; + if (PObj_needs_early_DOD_TEST(obj)) + ++interpreter->DOD_early_PMCs_seen; + if (*dod_flags & (PObj_is_special_PMC_FLAG << nm)) { if (((PMC*)obj)->pmc_ext) { - /* put it on the end of the list */ - interpreter->mark_ptr->next_for_GC = (PMC *)obj; + if (PObj_high_priority_DOD_TEST(obj) + && interpreter->dod_trace_ptr) { + PMC* tptr = interpreter->dod_trace_ptr; + /* Ugh, we have to check for self reference, otherwise + * we get a nasty circular loop. But, since whenever + * this block is executed, we're getting a nice + * optimization, I figure it's okay */ + if (tptr->next_for_GC == tptr) { + ((PMC*)obj)->next_for_GC = (PMC*)obj; + } + else { + /* put it at the head of the list */ + ((PMC*)obj)->next_for_GC = tptr->next_for_GC; + } + interpreter->dod_trace_ptr->next_for_GC = (PMC*)obj; + } + else { + /* put it on the end of the list */ + interpreter->dod_mark_ptr->next_for_GC = (PMC *)obj; - /* Explicitly make the tail of the linked list be - * self-referential */ - interpreter->mark_ptr = ((PMC*)obj)->next_for_GC = (PMC *)obj; + /* Explicitly make the tail of the linked list be + * self-referential */ + interpreter->dod_mark_ptr = ((PMC*)obj)->next_for_GC = (PMC *)obj; + } } else if (PObj_custom_mark_TEST(obj)) VTABLE_mark(interpreter, (PMC *) obj); - return; } } @@ -84,23 +110,42 @@ } # endif #endif + if (PObj_high_priority_DOD_TEST(obj) && interpreter->dod_trace_ptr) + PObj_high_priority_DOD_SET(interpreter->dod_trace_ptr); /* mark it live */ PObj_live_SET(obj); /* if object is a PMC and contains buffers or PMCs, then attach * the PMC to the chained mark list */ - if (PObj_is_special_PMC_TEST(obj)) { + if (*dod_flags & (PObj_is_special_PMC_FLAG << nm)) { if (((PMC*)obj)->pmc_ext) { - /* put it on the end of the list */ - interpreter->mark_ptr->next_for_GC = (PMC *)obj; + if (PObj_high_priority_DOD_TEST(obj) + && interpreter->dod_trace_ptr) { + PMC* tptr = interpreter->dod_trace_ptr; + /* Ugh, we have to check for self reference, otherwise + * we get a nasty circular loop. But, since whenever + * this block is executed, we're getting a nice + * optimization, I figure it's okay */ + if (tptr->next_for_GC == tptr) { + ((PMC*)obj)->next_for_GC = (PMC*)obj; + } + else { + /* put it at the head of the list */ + ((PMC*)obj)->next_for_GC = tptr->next_for_GC; + } + interpreter->dod_trace_ptr->next_for_GC = (PMC*)obj; + } + else { + /* put it on the end of the list */ + interpreter->dod_mark_ptr->next_for_GC = (PMC *)obj; - /* Explicitly make the tail of the linked list be - * self-referential */ - interpreter->mark_ptr = ((PMC*)obj)->next_for_GC = (PMC *)obj; + /* Explicitly make the tail of the linked list be + * self-referential */ + interpreter->dod_mark_ptr = ((PMC*)obj)->next_for_GC = (PMC *)obj; + } } else if (PObj_custom_mark_TEST(obj)) VTABLE_mark(interpreter, (PMC *) obj); - return; } #if GC_VERBOSE /* buffer GC_DEBUG stuff */ @@ -117,8 +162,10 @@ #endif -/* Do a full trace run and mark all the PMCs as active if they are */ -static void +/* Do a full trace run and mark all the PMCs as active if they are. + * Returns whether the run wasn't aborted (whether it is safe to + * proceed with GC) */ +static int trace_active_PMCs(struct Parrot_Interp *interpreter, int trace_stack) { PMC *current; @@ -134,7 +181,7 @@ struct Stash *stash = 0; /* We have to start somewhere, the interpreter globals is a good place */ - interpreter->mark_ptr = current = interpreter->iglobals; + interpreter->dod_mark_ptr = current = interpreter->iglobals; /* mark it as used */ pobject_lives(interpreter, (PObj *)interpreter->iglobals); @@ -194,20 +241,30 @@ #endif /* Okay, we've marked the whole root set, and should have a good-sized * list 'o things to look at. Run through it */ - trace_children(interpreter, current); + return trace_children(interpreter, current); } -static void +/* Returns whether the process wasn't aborted. */ +static int trace_children(struct Parrot_Interp *interpreter, PMC *current) { PMC *prev = NULL; unsigned i = 0; UINTVAL mask = PObj_is_PMC_ptr_FLAG | PObj_is_buffer_ptr_FLAG | PObj_custom_mark_FLAG; - + int lazy_dod = interpreter->lazy_dod; + for (; current != prev; current = current->next_for_GC) { UINTVAL bits = PObj_get_FLAGS(current) & mask; + if (lazy_dod && + interpreter->DOD_early_PMCs_seen >= interpreter->num_early_DOD_PMCs) { + return 0; + } + interpreter->dod_trace_ptr = current; + if (!PObj_needs_early_DOD_TEST(current)) + PObj_high_priority_DOD_CLEAR(current); + /* mark properties */ if (current->metadata) { pobject_lives(interpreter, (PObj *)current->metadata); @@ -250,6 +307,7 @@ prev = current; } + return 1; } /* Scan any buffers in S registers and other non-PMC places and mark @@ -453,9 +511,6 @@ UINTVAL free_arenas = 0, old_total_used = 0; #endif - /* We have no impatient things. Yet. */ - interpreter->has_early_DOD_PMCs = 0; - /* Run through all the buffer header pools and mark */ for (cur_arena = pool->last_Arena; NULL != cur_arena; cur_arena = cur_arena->prev) { @@ -497,13 +552,8 @@ { /* its live */ total_used++; -#if ARENA_DOD_FLAGS - if ((*dod_flags & (PObj_needs_early_DOD_FLAG << nm))) - interpreter->has_early_DOD_PMCs = 1; -#else +#if !ARENA_DOD_FLAGS PObj_live_CLEAR(b); - if (PObj_needs_early_DOD_TEST(b)) - interpreter->has_early_DOD_PMCs = 1; #endif } else { @@ -517,6 +567,8 @@ if (PObj_is_PMC_TEST(b)) { /* then destroy it here */ + if (PObj_high_priority_DOD_TEST(b)) + --interpreter->num_early_DOD_PMCs; if (PObj_active_destroy_TEST(b)) VTABLE_destroy(interpreter, (PMC *)b); @@ -699,7 +751,7 @@ /* See if we can find some unused headers */ void -Parrot_do_dod_run(struct Parrot_Interp *interpreter, int trace_stack) +Parrot_do_dod_run(struct Parrot_Interp *interpreter, UINTVAL flags) { struct Small_Object_Pool *header_pool; int j; @@ -711,6 +763,8 @@ } Parrot_block_DOD(interpreter); + interpreter->lazy_dod = flags & DOD_lazy_FLAG; + interpreter->dod_trace_ptr = NULL; #if ARENA_DOD_FLAGS clear_live_counter(interpreter, interpreter->arena_base->pmc_pool); for (j = 0; j < (INTVAL)interpreter->arena_base->num_sized; j++) { @@ -720,49 +774,51 @@ } #endif /* Now go trace the PMCs */ - trace_active_PMCs(interpreter, trace_stack); + if (trace_active_PMCs(interpreter, flags & DOD_trace_stack_FLAG)) { - /* And the buffers */ - trace_active_buffers(interpreter); + /* And the buffers */ + trace_active_buffers(interpreter); #if !TRACE_SYSTEM_AREAS # if GC_VERBOSE - /* whe, we don't trace stack and registers, we check after - * marking everything, if something was missed - * not - these could also be stale objects - */ - if (trace_stack) { + /* whe, we don't trace stack and registers, we check after + * marking everything, if something was missed + * not - these could also be stale objects + */ + if (flags & DOD_trace_stack_FLAG) { # if ! DISABLE_GC_DEBUG - CONSERVATIVE_POINTER_CHASING = 1; + CONSERVATIVE_POINTER_CHASING = 1; # endif - trace_system_areas(interpreter); + trace_system_areas(interpreter); # if ! DISABLE_GC_DEBUG - CONSERVATIVE_POINTER_CHASING = 0; + CONSERVATIVE_POINTER_CHASING = 0; # endif - } + } # endif #endif - /* Now put unused PMCs on the free list */ - header_pool = interpreter->arena_base->pmc_pool; - free_unused_pobjects(interpreter, header_pool); - total_free += header_pool->num_free_objects; - - /* And unused buffers on the free list */ - for (j = 0; j < (INTVAL)interpreter->arena_base->num_sized; j++) { - header_pool = interpreter->arena_base->sized_header_pools[j]; - if (header_pool) { + /* Now put unused PMCs on the free list */ + header_pool = interpreter->arena_base->pmc_pool; + free_unused_pobjects(interpreter, header_pool); + total_free += header_pool->num_free_objects; + + /* And unused buffers on the free list */ + for (j = 0; j < (INTVAL)interpreter->arena_base->num_sized; j++) { + header_pool = interpreter->arena_base->sized_header_pools[j]; + if (header_pool) { #ifdef GC_IS_MALLOC - used_cow(interpreter, header_pool, 0); + used_cow(interpreter, header_pool, 0); #endif - free_unused_pobjects(interpreter, header_pool); - total_free += header_pool->num_free_objects; + free_unused_pobjects(interpreter, header_pool); + total_free += header_pool->num_free_objects; #ifdef GC_IS_MALLOC - clear_cow(interpreter, header_pool, 0); + clear_cow(interpreter, header_pool, 0); #endif + } } } /* Note it */ interpreter->dod_runs++; + interpreter->dod_trace_ptr = NULL; Parrot_unblock_DOD(interpreter); return; } Index: interpreter.c =================================================================== RCS file: /cvs/public/parrot/interpreter.c,v retrieving revision 1.199 diff -u -r1.199 interpreter.c --- interpreter.c 28 Aug 2003 15:26:21 -0000 1.199 +++ interpreter.c 10 Sep 2003 04:37:06 -0000 @@ -865,7 +865,7 @@ */ Parrot_IOData_mark(interpreter, interpreter->piodata); - if (interpreter->has_early_DOD_PMCs) + if (interpreter->num_early_DOD_PMCs) free_unused_pobjects(interpreter, interpreter->arena_base->pmc_pool); /* we destroy all child interpreters and the last one too, @@ -1006,6 +1006,9 @@ break; case TOTAL_COPIED: ret = interpreter->memory_collected; + break; + case IMPATIENT_PMCS: + ret = interpreter->num_early_DOD_PMCs; break; } return ret; Index: resources.c =================================================================== RCS file: /cvs/public/parrot/resources.c,v retrieving revision 1.108 diff -u -r1.108 resources.c --- resources.c 28 Jul 2003 13:37:55 -0000 1.108 +++ resources.c 10 Sep 2003 04:37:07 -0000 @@ -106,13 +106,13 @@ interpreter->mem_allocs_since_last_collect++; } if (0 && GC_DEBUG(interpreter)) { - Parrot_do_dod_run(interpreter, 1); + Parrot_do_dod_run(interpreter, DOD_trace_stack_FLAG); if (pool->compact) { (*pool->compact) (interpreter, pool); } } if (pool->top_block->free < size) { - Parrot_do_dod_run(interpreter, 1); + Parrot_do_dod_run(interpreter, DOD_trace_stack_FLAG); /* Compact the pool if allowed and worthwhile */ if (pool->compact) { /* don't bother reclaiming if it's just chicken feed */ Index: smallobject.c =================================================================== RCS file: /cvs/public/parrot/smallobject.c,v retrieving revision 1.26 diff -u -r1.26 smallobject.c --- smallobject.c 26 Aug 2003 10:05:44 -0000 1.26 +++ smallobject.c 10 Sep 2003 04:37:07 -0000 @@ -68,7 +68,7 @@ if (pool->skip) pool->skip = 0; else { - Parrot_do_dod_run(interpreter, 1); + Parrot_do_dod_run(interpreter, DOD_trace_stack_FLAG); if (pool->num_free_objects <= pool->replenish_level) pool->skip = 1; } Index: string.c =================================================================== RCS file: /cvs/public/parrot/string.c,v retrieving revision 1.143 diff -u -r1.143 string.c --- string.c 27 Aug 2003 16:27:28 -0000 1.143 +++ string.c 10 Sep 2003 04:37:07 -0000 @@ -943,7 +943,7 @@ /* It's easy to forget that string comparison can trigger GC */ if (interpreter && GC_DEBUG(interpreter)) - Parrot_do_dod_run(interpreter, 1); + Parrot_do_dod_run(interpreter, DOD_trace_stack_FLAG); if (s1->type != s2->type || s1->encoding != s2->encoding) { s1 = string_transcode(interpreter, s1, NULL, string_unicode_type, @@ -1018,7 +1018,7 @@ /* trigger GC for debug */ if (interpreter && GC_DEBUG(interpreter)) - Parrot_do_dod_run(interpreter, 1); + Parrot_do_dod_run(interpreter, DOD_trace_stack_FLAG); if (s1->type != s2->type || s1->encoding != s2->encoding) { s1 = string_transcode(interpreter, s1, NULL, string_unicode_type, @@ -1080,7 +1080,7 @@ /* trigger GC for debug */ if (interpreter && GC_DEBUG(interpreter)) - Parrot_do_dod_run(interpreter, 1); + Parrot_do_dod_run(interpreter, DOD_trace_stack_FLAG); if (s1 && s2) { if (s1->type != s2->type || s1->encoding != s2->encoding) { @@ -1162,7 +1162,7 @@ /* trigger GC for debug */ if (interpreter && GC_DEBUG(interpreter)) - Parrot_do_dod_run(interpreter, 1); + Parrot_do_dod_run(interpreter, DOD_trace_stack_FLAG); if (s1 && s2) { if (s1->type != s2->type || s1->encoding != s2->encoding) { Index: classes/timer.pmc =================================================================== RCS file: /cvs/public/parrot/classes/timer.pmc,v retrieving revision 1.7 diff -u -r1.7 timer.pmc --- classes/timer.pmc 25 Aug 2003 09:46:23 -0000 1.7 +++ classes/timer.pmc 10 Sep 2003 04:37:07 -0000 @@ -253,7 +253,7 @@ t->self = SELF; SELF->cache.struct_val = t; PObj_active_destroy_SET(SELF); - interpreter->has_early_DOD_PMCs = 1; + interpreter->num_early_DOD_PMCs++; } void init_pmc(PMC *init) { Index: include/parrot/dod.h =================================================================== RCS file: /cvs/public/parrot/include/parrot/dod.h,v retrieving revision 1.11 diff -u -r1.11 dod.h --- include/parrot/dod.h 28 Jul 2003 13:38:00 -0000 1.11 +++ include/parrot/dod.h 10 Sep 2003 04:37:07 -0000 @@ -40,7 +40,12 @@ #define Parrot_is_blocked_GC(interpreter) \ ((interpreter)->GC_block_level) -void Parrot_do_dod_run(struct Parrot_Interp *, int trace_stack); +enum { + DOD_trace_stack_FLAG = 1 << 0, + DOD_lazy_FLAG = 1 << 1 +}; + +void Parrot_do_dod_run(struct Parrot_Interp *, UINTVAL flags); void trace_system_areas(struct Parrot_Interp *); void trace_mem_block(struct Parrot_Interp *, size_t, size_t); Index: include/parrot/interpreter.h =================================================================== RCS file: /cvs/public/parrot/include/parrot/interpreter.h,v retrieving revision 1.85 diff -u -r1.85 interpreter.h --- include/parrot/interpreter.h 28 Aug 2003 15:26:24 -0000 1.85 +++ include/parrot/interpreter.h 10 Sep 2003 04:37:07 -0000 @@ -188,14 +188,19 @@ /* per interpreter global vars */ INTVAL world_inited; /* Parrot_init is done */ - PMC *mark_ptr; /* last PMC marked used in DOD runs */ PMC *iglobals; /* SArray of PMCs, containing: */ /* 0: PMC *Parrot_base_classname_hash; hash containing name->base_type */ /* 1: PMC *Parrot_compreg_hash; hash containing assembler/compilers */ /* 2: PMC *Argv; list of argv */ /* 3: PMC *Env; hash_like Env PMC */ /* 4: PMC *ParrotInterpreter that's me */ - int has_early_DOD_PMCs; /* Flag that some want immediate destruction */ + UINTVAL num_early_DOD_PMCs; /* how many want immediate destruction */ + UINTVAL DOD_early_PMCs_seen; /* how many that want immediate destruction + * has DOD seen */ + PMC *dod_mark_ptr; /* last PMC marked used in DOD runs */ + PMC *dod_trace_ptr; /* last PMC trace_children was called on */ + int lazy_dod; /* flag indicating whether we should stop + when we find all impatient pmcs */ } Interp; /* &gen_from_enum(iglobals.pasm) */ Index: include/parrot/pobj.h =================================================================== RCS file: /cvs/public/parrot/include/parrot/pobj.h,v retrieving revision 1.28 diff -u -r1.28 pobj.h --- include/parrot/pobj.h 28 Aug 2003 13:44:25 -0000 1.28 +++ include/parrot/pobj.h 10 Sep 2003 04:37:07 -0000 @@ -198,7 +198,7 @@ PObj_active_destroy_FLAG = 1 << 22, /* For debugging, report when this buffer gets moved around */ PObj_report_FLAG = 1 << 23, - + /* PMC specific FLAGs */ /* Set to true if the PMC data pointer points to something that @@ -218,12 +218,14 @@ */ b_PObj_is_special_PMC_FLAG = 1 << 26, - b_PObj_needs_early_DOD_FLAG = 1 << 27, + /* This PObj is connected by some route to a "needs_early_DOD" object */ + PObj_high_priority_DOD_FLAG = 1 << 27, + PObj_needs_early_DOD_FLAG = (1 << 27 | 1 << 28), /* True if the PMC is a class */ - PObj_is_class_FLAG = 1 << 28, + PObj_is_class_FLAG = 1 << 29, /* True if the PMC is a parrot object */ - PObj_is_object_FLAG = 1 << 29 + PObj_is_object_FLAG = 1 << 30 } PObj_flags; @@ -240,7 +242,6 @@ # define d_PObj_live_FLAG 0x01 # define d_PObj_on_free_list_FLAG 0x02 # define d_PObj_is_special_PMC_FLAG 0x04 -# define d_PObj_needs_early_DOD_FLAG 0x08 /* * arenas are constant sized ~32 byte object size, ~128K objects @@ -297,14 +298,12 @@ # define PObj_live_FLAG d_PObj_live_FLAG # define PObj_on_free_list_FLAG d_PObj_on_free_list_FLAG # define PObj_is_special_PMC_FLAG d_PObj_is_special_PMC_FLAG -# define PObj_needs_early_DOD_FLAG d_PObj_needs_early_DOD_FLAG #else # define PObj_live_FLAG b_PObj_live_FLAG # define PObj_on_free_list_FLAG b_PObj_on_free_list_FLAG # define PObj_is_special_PMC_FLAG b_PObj_is_special_PMC_FLAG -# define PObj_needs_early_DOD_FLAG b_PObj_needs_early_DOD_FLAG # define DOD_flag_TEST(flag, o) PObj_flag_TEST(flag, o) # define DOD_flag_SET(flag, o) PObj_flag_SET(flag, o) @@ -341,6 +340,10 @@ #define PObj_report_SET(o) PObj_flag_SET(report, o) #define PObj_report_CLEAR(o) PObj_flag_CLEAR(report, o) +#define PObj_high_priority_DOD_TEST(o) PObj_flag_TEST(high_priority_DOD, o) +#define PObj_high_priority_DOD_SET(o) PObj_flag_SET(high_priority_DOD, o) +#define PObj_high_priority_DOD_CLEAR(o) PObj_flag_CLEAR(high_priority_DOD, o) + #define PObj_on_free_list_TEST(o) DOD_flag_TEST(on_free_list, o) #define PObj_on_free_list_SET(o) DOD_flag_SET(on_free_list, o) #define PObj_on_free_list_CLEAR(o) DOD_flag_CLEAR(on_free_list, o) @@ -361,9 +364,9 @@ #define PObj_sysmem_SET(o) PObj_flag_SET(sysmem, o) #define PObj_sysmem_CLEAR(o) PObj_flag_CLEAR(sysmem, o) -#define PObj_needs_early_DOD_TEST(o) DOD_flag_TEST(needs_early_DOD, o) -#define PObj_needs_early_DOD_SET(o) DOD_flag_SET(needs_early_DOD, o) -#define PObj_needs_early_DOD_CLEAR(o) DOD_flag_CLEAR(needs_early_DOD, o) +#define PObj_needs_early_DOD_TEST(o) PObj_flag_TEST(needs_early_DOD, o) +#define PObj_needs_early_DOD_SET(o) PObj_flag_SET(needs_early_DOD, o) +#define PObj_needs_early_DOD_CLEAR(o) PObj_flag_CLEAR(needs_early_DOD, o) #define PObj_special_SET(flag, o) do { \ PObj_flag_SET(flag, o); \ Index: include/parrot/resources.h =================================================================== RCS file: /cvs/public/parrot/include/parrot/resources.h,v retrieving revision 1.44 diff -u -r1.44 resources.h --- include/parrot/resources.h 21 Jul 2003 18:00:42 -0000 1.44 +++ include/parrot/resources.h 10 Sep 2003 04:37:07 -0000 @@ -82,6 +82,7 @@ #define HEADER_ALLOCS_SINCE_COLLECT 8 #define MEM_ALLOCS_SINCE_COLLECT 9 #define TOTAL_COPIED 10 +#define IMPATIENT_PMCS 11 /* &end_gen */ Index: io/io.c =================================================================== RCS file: /cvs/public/parrot/io/io.c,v retrieving revision 1.53 diff -u -r1.53 io.c --- io/io.c 2 Sep 2003 16:41:14 -0000 1.53 +++ io/io.c 10 Sep 2003 04:37:07 -0000 @@ -748,12 +748,12 @@ INTVAL i; ParrotIOTable table = piodata->table; - /* XXX boe: Parrot_really_destroy might call us with mark_ptr not + /* XXX boe: Parrot_really_destroy might call us with pmc_mark_ptr not * set. This is neccessary until destruction ordering prevents * the premature destruction of the standardhandles */ - if (!interpreter->mark_ptr) - interpreter->mark_ptr = table[0]; + if (!interpreter->dod_mark_ptr) + interpreter->dod_mark_ptr = table[0]; for (i = 0; i < PIO_NR_OPEN; i++) { if (table[i]) { Index: t/op/gc.t =================================================================== RCS file: /cvs/public/parrot/t/op/gc.t,v retrieving revision 1.5 diff -u -r1.5 gc.t --- t/op/gc.t 1 Jul 2003 23:08:14 -0000 1.5 +++ t/op/gc.t 10 Sep 2003 04:37:07 -0000 @@ -35,10 +35,10 @@ interpinfo I1, 2 # How many DOD runs have we done already? new P0, .PerlUndef needs_destroy P0 + new P0, .PerlUndef # kill object sweep 0 interpinfo I2, 2 # Should be one more now sub I3, I2, I1 - new P0, .PerlUndef # kill 1st object sweep 0 interpinfo I4, 2 # Should be same as last sub I5, I4, I2