Leopold Toetsch writes:
> Luke Palmer <[EMAIL PROTECTED]> wrote:
> 
> > In any case, seeing that depth first case (see the footnote) has given
> > me even more hope that I won't be agonizing over scope exit.
> 
> Can you summarize your scheme again please WRT this and other
> enhancements. I'm somewhat lost in all the improvements that were
> proposed since your original.

Alright, here's a patch that implements it.  The current scheme is
actually quite a bit simpler than the one I originally proposed.  It
should provide much better performance, too.

Bear with me, because I don't know my way around the DOD very well.
First, do I increment num_early_DOD_PMCs in the right place?  That's
where it was set to 1 before...

Also, the critical block that makes this an optimization is missing,
marked with an XXX.  I didn't implement it because I don't really know
the control flow of DOD, so I didn't know how to abort cleanly.  Can
someone give me some hints here?

Other than those few, but unignorable, caveats, Enjoy!


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        5 Sep 2003 11:28:24 -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       5 Sep 2003 11:28:24 -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,
+    b_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;
 
@@ -340,6 +342,10 @@
 #define PObj_report_TEST(o) PObj_flag_TEST(report, o)
 #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)
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        5 Sep 2003 11:28:24 -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: 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       5 Sep 2003 11:28:24 -0000
@@ -43,19 +43,34 @@
     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 (*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_early_PMCs_seen 
+             && interpreter->dod_trace_ptr) {
+                /* put it at the head of the list */
+                ((PMC*)obj)->next_for_GC = interpreter->dod_trace_ptr
+                                           ->next_for_GC->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);
@@ -84,6 +99,8 @@
     }
 #  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
@@ -91,12 +108,22 @@
      */
     if (PObj_is_special_PMC_TEST(obj)) {
         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_early_PMCs_seen 
+             && interpreter->dod_trace_ptr) {
+                /* put it at the head of the list */
+                ((PMC*)obj)->next_for_GC = interpreter->dod_trace_ptr
+                                           ->next_for_GC->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);
@@ -134,7 +161,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);
@@ -204,7 +231,13 @@
     unsigned i = 0;
     UINTVAL mask = PObj_is_PMC_ptr_FLAG | PObj_is_buffer_ptr_FLAG
         | PObj_custom_mark_FLAG;
-
+    
+    if (interpreter->DOD_early_PMCs_seen >= interpreter->num_early_DOD_PMCs)
+        ;  /* XXX (lp): abort DOD and set a flag saying "no GC allowed" */
+    
+    PObj_high_priority_DOD_CLEAR(current);
+    interpreter->dod_trace_ptr = current;
+    
     for (;  current != prev; current = current->next_for_GC) {
         UINTVAL bits = PObj_get_FLAGS(current) & mask;
 
@@ -454,7 +487,7 @@
 #endif
 
     /* We have no impatient things. Yet. */
-    interpreter->has_early_DOD_PMCs = 0;
+    interpreter->num_early_DOD_PMCs = 0;
 
     /* Run through all the buffer header pools and mark */
     for (cur_arena = pool->last_Arena;
@@ -499,11 +532,11 @@
                 total_used++;
 #if ARENA_DOD_FLAGS
                 if ((*dod_flags & (PObj_needs_early_DOD_FLAG << nm)))
-                    interpreter->has_early_DOD_PMCs = 1;
+                    ++interpreter->num_early_DOD_PMCs;
 #else
                 PObj_live_CLEAR(b);
                 if (PObj_needs_early_DOD_TEST(b))
-                    interpreter->has_early_DOD_PMCs = 1;
+                    ++interpreter->num_early_DOD_PMCs;
 #endif
             }
             else {
@@ -699,7 +732,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 +744,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,7 +755,7 @@
     }
 #endif
     /* Now go trace the PMCs */
-    trace_active_PMCs(interpreter, trace_stack);
+    trace_active_PMCs(interpreter, flags & DOD_trace_stack_FLAG);
 
     /* And the buffers */
     trace_active_buffers(interpreter);
@@ -730,7 +765,7 @@
      * marking everything, if something was missed
      * not - these could also be stale objects
      */
-    if (trace_stack) {
+    if (flags & DOD_trace_stack_FLAG) {
 #  if ! DISABLE_GC_DEBUG
         CONSERVATIVE_POINTER_CHASING = 1;
 #  endif
@@ -763,6 +798,7 @@
     }
     /* 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       5 Sep 2003 11:28:24 -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,
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 5 Sep 2003 11:28:24 -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       5 Sep 2003 11:28:24 -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    5 Sep 2003 11:28:24 -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   5 Sep 2003 11:28:24 -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: 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     5 Sep 2003 11:28:24 -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 dod_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: 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    5 Sep 2003 11:28:24 -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,7 +909,7 @@
 
 op needs_destroy(in PMC) {
    PObj_needs_early_DOD_SET($1);
-   interpreter->has_early_DOD_PMCs = 1;
+   interpreter->num_early_DOD_PMCs = 1;
   goto NEXT();
 }
 

Reply via email to