Back to index

plt-scheme  4.2.1
mark_rts.c
Go to the documentation of this file.
00001 /* 
00002  * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
00003  * Copyright (c) 1991-1994 by Xerox Corporation.  All rights reserved.
00004  *
00005  * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
00006  * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
00007  *
00008  * Permission is hereby granted to use or copy this program
00009  * for any purpose,  provided the above notices are retained on all copies.
00010  * Permission to modify the code and to distribute modified code is granted,
00011  * provided the above notices are retained, and a notice that the code was
00012  * modified is included with the above copyright notice.
00013  */
00014 # include <stdio.h>
00015 # include "private/gc_priv.h"
00016 
00017 /* Data structure for list of root sets.                       */
00018 /* We keep a hash table, so that we can filter out duplicate additions.      */
00019 /* Under Win32, we need to do a better job of filtering overlaps, so  */
00020 /* we resort to sequential search, and pay the price.                 */
00021 /* This is really declared in gc_priv.h:
00022 struct roots {
00023        ptr_t r_start;
00024        ptr_t r_end;
00025  #     if !defined(MSWIN32) && !defined(MSWINCE)
00026          struct roots * r_next;
00027  #     endif
00028        GC_bool r_tmp;
00029               -- Delete before registering new dynamic libraries
00030 };
00031 
00032 struct roots GC_static_roots[MAX_ROOT_SETS];
00033 */
00034 
00035 int GC_no_dls = 0;   /* Register dynamic library data segments.       */
00036 
00037 static int n_root_sets = 0;
00038 
00039        /* GC_static_roots[0..n_root_sets) contains the valid root sets. */
00040 
00041 /* PLTSCHEME: hook for last roots; need to mark copies of the stack */
00042 void (*GC_push_last_roots)() = 0;
00043 
00044 # if !defined(NO_DEBUGGING)
00045 /* For debugging:    */
00046 void GC_print_static_roots()
00047 {
00048     register int i;
00049     size_t total = 0;
00050     
00051     for (i = 0; i < n_root_sets; i++) {
00052         GC_printf2("From 0x%lx to 0x%lx ",
00053                  (unsigned long) GC_static_roots[i].r_start,
00054                  (unsigned long) GC_static_roots[i].r_end);
00055         if (GC_static_roots[i].r_tmp) {
00056             GC_printf0(" (temporary)\n");
00057         } else {
00058             GC_printf0("\n");
00059         }
00060         total += GC_static_roots[i].r_end - GC_static_roots[i].r_start;
00061     }
00062     GC_printf1("Total size: %ld\n", (unsigned long) total);
00063     if (GC_root_size != total) {
00064        GC_printf1("GC_root_size incorrect: %ld!!\n",
00065                  (unsigned long) GC_root_size);
00066     }
00067 }
00068 # endif /* NO_DEBUGGING */
00069 
00070 /* Primarily for debugging support:       */
00071 /* Is the address p in one of the registered static                   */
00072 /* root sections?                                              */
00073 GC_bool GC_is_static_root(p)
00074 ptr_t p;
00075 {
00076     static int last_root_set = MAX_ROOT_SETS;
00077     register int i;
00078     
00079     
00080     if (last_root_set < n_root_sets
00081        && p >= GC_static_roots[last_root_set].r_start
00082         && p < GC_static_roots[last_root_set].r_end) return(TRUE);
00083     for (i = 0; i < n_root_sets; i++) {
00084        if (p >= GC_static_roots[i].r_start
00085             && p < GC_static_roots[i].r_end) {
00086             last_root_set = i;
00087             return(TRUE);
00088         }
00089     }
00090     return(FALSE);
00091 }
00092 
00093 #if !defined(MSWIN32) && !defined(MSWINCE)
00094 /* 
00095 #   define LOG_RT_SIZE 6
00096 #   define RT_SIZE (1 << LOG_RT_SIZE)  -- Power of 2, may be != MAX_ROOT_SETS
00097 
00098     struct roots * GC_root_index[RT_SIZE];
00099        -- Hash table header.  Used only to check whether a range is
00100        -- already present.
00101        -- really defined in gc_priv.h
00102 */
00103 
00104 static int rt_hash(addr)
00105 char * addr;
00106 {
00107     word result = (word) addr;
00108 #   if CPP_WORDSZ > 8*LOG_RT_SIZE
00109        result ^= result >> 8*LOG_RT_SIZE;
00110 #   endif
00111 #   if CPP_WORDSZ > 4*LOG_RT_SIZE
00112        result ^= result >> 4*LOG_RT_SIZE;
00113 #   endif
00114     result ^= result >> 2*LOG_RT_SIZE;
00115     result ^= result >> LOG_RT_SIZE;
00116     result &= (RT_SIZE-1);
00117     return(result);
00118 }
00119 
00120 /* Is a range starting at b already in the table? If so return a      */
00121 /* pointer to it, else NIL.                                    */
00122 struct roots * GC_roots_present(b)
00123 char *b;
00124 {
00125     register int h = rt_hash(b);
00126     register struct roots *p = GC_root_index[h];
00127     
00128     while (p != 0) {
00129         if (p -> r_start == (ptr_t)b) return(p);
00130         p = p -> r_next;
00131     }
00132     return(FALSE);
00133 }
00134 
00135 /* Add the given root structure to the index. */
00136 static void add_roots_to_index(p)
00137 struct roots *p;
00138 {
00139     register int h = rt_hash(p -> r_start);
00140     
00141     p -> r_next = GC_root_index[h];
00142     GC_root_index[h] = p;
00143 }
00144 
00145 # else /* MSWIN32 || MSWINCE */
00146 
00147 #   define add_roots_to_index(p)
00148 
00149 # endif
00150 
00151 
00152 
00153 
00154 word GC_root_size = 0;
00155 
00156 void GC_add_roots(b, e)
00157 char * b; char * e;
00158 {
00159     DCL_LOCK_STATE;
00160     
00161     DISABLE_SIGNALS();
00162     LOCK();
00163     GC_add_roots_inner(b, e, FALSE);
00164     UNLOCK();
00165     ENABLE_SIGNALS();
00166 }
00167 
00168 
00169 /* Add [b,e) to the root set.  Adding the same interval a second time */
00170 /* is a moderately fast noop, and hence benign.  We do not handle     */
00171 /* different but overlapping intervals efficiently.  (We do handle    */
00172 /* them correctly.)                                            */
00173 /* Tmp specifies that the interval may be deleted before              */
00174 /* reregistering dynamic libraries.                                   */ 
00175 void GC_add_roots_inner(b, e, tmp)
00176 char * b; char * e;
00177 GC_bool tmp;
00178 {
00179     struct roots * old;
00180     
00181 /* PLTSCHEME: always merge overlapping: */
00182 #   if 1 || defined(MSWIN32) || defined(MSWINCE)
00183       /* Spend the time to ensure that there are no overlapping       */
00184       /* or adjacent intervals.                                */
00185       /* This could be done faster with e.g. a                 */
00186       /* balanced tree.  But the execution time here is        */
00187       /* virtually guaranteed to be dominated by the time it   */
00188       /* takes to scan the roots.                       */
00189       {
00190         register int i;
00191         
00192         for (i = 0; i < n_root_sets; i++) {
00193             old = GC_static_roots + i;
00194             if ((ptr_t)b <= old -> r_end && (ptr_t)e >= old -> r_start
00195               && tmp == old -> r_tmp) { /* PLTSCHEME: merge only same kinds */
00196                 if ((ptr_t)b < old -> r_start) {
00197                     old -> r_start = (ptr_t)b;
00198                     GC_root_size += (old -> r_start - (ptr_t)b);
00199                 }
00200                 if ((ptr_t)e > old -> r_end) {
00201                     old -> r_end = (ptr_t)e;
00202                     GC_root_size += ((ptr_t)e - old -> r_end);
00203                 }
00204                 old -> r_tmp &= tmp;
00205                 break;
00206             }
00207         }
00208         if (i < n_root_sets) {
00209           /* merge other overlapping intervals */
00210             struct roots *other;
00211             
00212             for (i++; i < n_root_sets; i++) {
00213               other = GC_static_roots + i;
00214               b = (char *)(other -> r_start);
00215               e = (char *)(other -> r_end);
00216              tmp = other -> r_tmp; /* PLTSCHEME */
00217               if ((ptr_t)b <= old -> r_end && (ptr_t)e >= old -> r_start
00218                 && tmp == old -> r_tmp) {  /* PLTSCHEME: merge only same kinds */
00219                 if ((ptr_t)b < old -> r_start) {
00220                     old -> r_start = (ptr_t)b;
00221                     GC_root_size += (old -> r_start - (ptr_t)b);
00222                 }
00223                 if ((ptr_t)e > old -> r_end) {
00224                     old -> r_end = (ptr_t)e;
00225                     GC_root_size += ((ptr_t)e - old -> r_end);
00226                 }
00227                 old -> r_tmp &= other -> r_tmp;
00228                 /* Delete this entry. */
00229                   GC_root_size -= (other -> r_end - other -> r_start);
00230                   other -> r_start = GC_static_roots[n_root_sets-1].r_start;
00231                   other -> r_end = GC_static_roots[n_root_sets-1].r_end;
00232                                   n_root_sets--;
00233               }
00234             }
00235           return;
00236         }
00237       }
00238 #   else
00239       old = GC_roots_present(b);
00240       if (old != 0) {
00241         if ((ptr_t)e <= old -> r_end) /* already there */ return;
00242         /* else extend */
00243         GC_root_size += (ptr_t)e - old -> r_end;
00244         old -> r_end = (ptr_t)e;
00245         return;
00246       }
00247 #   endif
00248     if (n_root_sets == MAX_ROOT_SETS) {
00249         ABORT("Too many root sets\n");
00250     }
00251     GC_static_roots[n_root_sets].r_start = (ptr_t)b;
00252     GC_static_roots[n_root_sets].r_end = (ptr_t)e;
00253     GC_static_roots[n_root_sets].r_tmp = tmp;
00254 #   if !defined(MSWIN32) && !defined(MSWINCE)
00255       GC_static_roots[n_root_sets].r_next = 0;
00256 #   endif
00257     add_roots_to_index(GC_static_roots + n_root_sets);
00258     GC_root_size += (ptr_t)e - (ptr_t)b;
00259     n_root_sets++;
00260 }
00261 
00262 static GC_bool roots_were_cleared = FALSE;
00263 
00264 void GC_clear_roots GC_PROTO((void))
00265 {
00266     DCL_LOCK_STATE;
00267     
00268     DISABLE_SIGNALS();
00269     LOCK();
00270     roots_were_cleared = TRUE;
00271     n_root_sets = 0;
00272     GC_root_size = 0;
00273 #   if !defined(MSWIN32) && !defined(MSWINCE)
00274     {
00275        register int i;
00276        
00277        for (i = 0; i < RT_SIZE; i++) GC_root_index[i] = 0;
00278     }
00279 #   endif
00280     UNLOCK();
00281     ENABLE_SIGNALS();
00282 }
00283 
00284 /* Internal use only; lock held.   */
00285 static void GC_remove_root_at_pos(i) 
00286 int i;
00287 {
00288     GC_root_size -= (GC_static_roots[i].r_end - GC_static_roots[i].r_start);
00289     GC_static_roots[i].r_start = GC_static_roots[n_root_sets-1].r_start;
00290     GC_static_roots[i].r_end = GC_static_roots[n_root_sets-1].r_end;
00291     GC_static_roots[i].r_tmp = GC_static_roots[n_root_sets-1].r_tmp;
00292     n_root_sets--;
00293 }
00294 
00295 #if !defined(MSWIN32) && !defined(MSWINCE)
00296 static void GC_rebuild_root_index()
00297 {
00298     register int i;
00299        
00300     for (i = 0; i < RT_SIZE; i++) GC_root_index[i] = 0;
00301     for (i = 0; i < n_root_sets; i++)
00302        add_roots_to_index(GC_static_roots + i);
00303 }
00304 #endif
00305 
00306 /* Internal use only; lock held.   */
00307 void GC_remove_tmp_roots()
00308 {
00309     register int i;
00310     
00311     for (i = 0; i < n_root_sets; ) {
00312        if (GC_static_roots[i].r_tmp) {
00313             GC_remove_root_at_pos(i);
00314        } else {
00315            i++;
00316     }
00317     }
00318     #if !defined(MSWIN32) && !defined(MSWINCE)
00319     GC_rebuild_root_index();
00320     #endif
00321 }
00322 
00323 #if !defined(MSWIN32) && !defined(MSWINCE)
00324 void GC_remove_roots(b, e)
00325 char * b; char * e;
00326 {
00327     DCL_LOCK_STATE;
00328     
00329     DISABLE_SIGNALS();
00330     LOCK();
00331     GC_remove_roots_inner(b, e);
00332     UNLOCK();
00333     ENABLE_SIGNALS();
00334 }
00335 
00336 /* Should only be called when the lock is held */
00337 void GC_remove_roots_inner(b,e)
00338 char * b; char * e;
00339 {
00340     int i;
00341     for (i = 0; i < n_root_sets; ) {
00342        if (GC_static_roots[i].r_start >= (ptr_t)b && GC_static_roots[i].r_end <= (ptr_t)e) {
00343             GC_remove_root_at_pos(i);
00344        } else {
00345            i++;
00346        }
00347     }
00348     GC_rebuild_root_index();
00349 }
00350 #endif /* !defined(MSWIN32) && !defined(MSWINCE) */
00351 
00352 #if defined(MSWIN32) || defined(_WIN32_WCE_EMULATION)
00353 /* Workaround for the OS mapping and unmapping behind our back:              */
00354 /* Is the address p in one of the temporary static root sections?     */
00355 GC_bool GC_is_tmp_root(p)
00356 ptr_t p;
00357 {
00358     static int last_root_set = MAX_ROOT_SETS;
00359     register int i;
00360     
00361     if (last_root_set < n_root_sets
00362        && p >= GC_static_roots[last_root_set].r_start
00363         && p < GC_static_roots[last_root_set].r_end)
00364        return GC_static_roots[last_root_set].r_tmp;
00365     for (i = 0; i < n_root_sets; i++) {
00366        if (p >= GC_static_roots[i].r_start
00367             && p < GC_static_roots[i].r_end) {
00368             last_root_set = i;
00369             return GC_static_roots[i].r_tmp;
00370         }
00371     }
00372     return(FALSE);
00373 }
00374 #endif /* MSWIN32 || _WIN32_WCE_EMULATION */
00375 
00376 ptr_t GC_approx_sp()
00377 {
00378     VOLATILE word dummy;
00379 
00380     dummy = 42;      /* Force stack to grow if necessary.      Otherwise the */
00381               /* later accesses might cause the kernel to think we're */
00382               /* doing something wrong.                        */
00383 #   ifdef _MSC_VER
00384 #     pragma warning(disable:4172)
00385 #   endif
00386     return((ptr_t)(&dummy));
00387 #   ifdef _MSC_VER
00388 #     pragma warning(default:4172)
00389 #   endif
00390 }
00391 
00392 /*
00393  * Data structure for excluded static roots.
00394  * Real declaration is in gc_priv.h.
00395 
00396 struct exclusion {
00397     ptr_t e_start;
00398     ptr_t e_end;
00399 };
00400 
00401 struct exclusion GC_excl_table[MAX_EXCLUSIONS];
00402                                    -- Array of exclusions, ascending
00403                                    -- address order.
00404 */
00405 
00406 size_t GC_excl_table_entries = 0;  /* Number of entries in use.         */
00407 
00408 /* Return the first exclusion range that includes an address >= start_addr */
00409 /* Assumes the exclusion table contains at least one entry (namely the          */
00410 /* GC data structures).                                                  */
00411 struct exclusion * GC_next_exclusion(start_addr)
00412 ptr_t start_addr;
00413 {
00414     size_t low = 0;
00415     size_t high = GC_excl_table_entries - 1;
00416     size_t mid;
00417 
00418     while (high > low) {
00419        mid = (low + high) >> 1;
00420        /* low <= mid < high */
00421        if ((word) GC_excl_table[mid].e_end <= (word) start_addr) {
00422            low = mid + 1;
00423        } else {
00424            high = mid;
00425        }
00426     }
00427     if ((word) GC_excl_table[low].e_end <= (word) start_addr) return 0;
00428     return GC_excl_table + low;
00429 }
00430 
00431 void GC_exclude_static_roots(start, finish)
00432 GC_PTR start;
00433 GC_PTR finish;
00434 {
00435     struct exclusion * next;
00436     size_t next_index, i;
00437 
00438     if (0 == GC_excl_table_entries) {
00439        next = 0;
00440     } else {
00441        next = GC_next_exclusion(start);
00442     }
00443     if (0 != next) {
00444       if ((word)(next -> e_start) < (word) finish) {
00445        /* incomplete error check. */
00446        ABORT("exclusion ranges overlap");
00447       }  
00448       if ((word)(next -> e_start) == (word) finish) {
00449         /* extend old range backwards     */
00450           next -> e_start = (ptr_t)start;
00451          return;
00452       }
00453       next_index = next - GC_excl_table;
00454       for (i = GC_excl_table_entries; i > next_index; --i) {
00455        GC_excl_table[i] = GC_excl_table[i-1];
00456       }
00457     } else {
00458       next_index = GC_excl_table_entries;
00459     }
00460     if (GC_excl_table_entries == MAX_EXCLUSIONS) ABORT("Too many exclusions");
00461     GC_excl_table[next_index].e_start = (ptr_t)start;
00462     GC_excl_table[next_index].e_end = (ptr_t)finish;
00463     ++GC_excl_table_entries;
00464 }
00465 
00466 /* Invoke push_conditional on ranges that are not excluded. */
00467 void GC_push_conditional_with_exclusions(bottom, top, all)
00468 ptr_t bottom;
00469 ptr_t top;
00470 int all;
00471 {
00472     struct exclusion * next;
00473     ptr_t excl_start;
00474 
00475     while (bottom < top) {
00476         next = GC_next_exclusion(bottom);
00477        if (0 == next || (excl_start = next -> e_start) >= top) {
00478            GC_push_conditional(bottom, top, all);
00479            return;
00480        }
00481        if (excl_start > bottom) GC_push_conditional(bottom, excl_start, all);
00482        bottom = next -> e_end;
00483     }
00484 }
00485 
00486 /*
00487  * In the absence of threads, push the stack contents.
00488  * In the presence of threads, push enough of the current stack
00489  * to ensure that callee-save registers saved in collector frames have been
00490  * seen.
00491  */
00492 void GC_push_current_stack(cold_gc_frame)
00493 ptr_t cold_gc_frame;
00494 {
00495 #   if defined(THREADS)
00496        if (0 == cold_gc_frame) return;
00497 #       ifdef STACK_GROWS_DOWN
00498          GC_push_all_eager(GC_approx_sp(), cold_gc_frame);
00499          /* For IA64, the register stack backing store is handled     */
00500          /* in the thread-specific code.                       */
00501 #       else
00502          GC_push_all_eager( cold_gc_frame, GC_approx_sp() );
00503 #       endif
00504 #   else
00505 #      ifdef STACK_GROWS_DOWN
00506            GC_push_all_stack_partially_eager( GC_approx_sp(), GC_stackbottom,
00507                                           cold_gc_frame );
00508 #          ifdef IA64
00509              /* We also need to push the register stack backing store. */
00510              /* This should really be done in the same way as the     */
00511              /* regular stack.  For now we fudge it a bit.            */
00512              /* Note that the backing store grows up, so we can't use */
00513              /* GC_push_all_stack_partially_eager.                    */
00514              {
00515               extern word GC_save_regs_ret_val;
00516                      /* Previously set to backing store pointer.      */
00517               ptr_t bsp = (ptr_t) GC_save_regs_ret_val;
00518                ptr_t cold_gc_bs_pointer;
00519               if (GC_all_interior_pointers) {
00520                  cold_gc_bs_pointer = bsp - 2048;
00521                 if (cold_gc_bs_pointer < BACKING_STORE_BASE) {
00522                   cold_gc_bs_pointer = BACKING_STORE_BASE;
00523                 } else {
00524                   GC_push_all_stack(BACKING_STORE_BASE, cold_gc_bs_pointer);
00525                 }
00526               } else {
00527                 cold_gc_bs_pointer = BACKING_STORE_BASE;
00528               }
00529               GC_push_all_eager(cold_gc_bs_pointer, bsp);
00530               /* All values should be sufficiently aligned that we    */
00531               /* dont have to worry about the boundary.        */
00532              }
00533 #          endif
00534 #       else
00535            GC_push_all_stack_partially_eager( GC_stackbottom, GC_approx_sp(),
00536                                           cold_gc_frame );
00537 #       endif
00538 #   endif /* !THREADS */
00539 }
00540 
00541 /*
00542  * Push GC internal roots.  Only called if there is some reason to believe
00543  * these would not otherwise get registered.
00544  */
00545 void GC_push_gc_structures GC_PROTO((void))
00546 {
00547     GC_push_finalizer_structures();
00548     GC_push_stubborn_structures();
00549 #   if defined(THREADS)
00550       GC_push_thread_structures();
00551 #   endif
00552 }
00553 
00554 #ifdef THREAD_LOCAL_ALLOC
00555   void GC_mark_thread_local_free_lists();
00556 #endif
00557 
00558 void GC_cond_register_dynamic_libraries()
00559 {
00560 # if (defined(DYNAMIC_LOADING) || defined(MSWIN32) || defined(MSWINCE) \
00561      || defined(PCR)) && !defined(SRC_M3)
00562     GC_remove_tmp_roots();
00563     if (!GC_no_dls) GC_register_dynamic_libraries();
00564 # else
00565     GC_no_dls = TRUE;
00566 # endif
00567 }
00568 
00569 /*
00570  * Call the mark routines (GC_tl_push for a single pointer, GC_push_conditional
00571  * on groups of pointers) on every top level accessible pointer.
00572  * If all is FALSE, arrange to push only possibly altered values.
00573  * Cold_gc_frame is an address inside a GC frame that
00574  * remains valid until all marking is complete.
00575  * A zero value indicates that it's OK to miss some
00576  * register values.
00577  */
00578 void GC_push_roots(all, cold_gc_frame)
00579 GC_bool all;
00580 ptr_t cold_gc_frame;
00581 {
00582     int i;
00583     int kind;
00584 
00585     /*
00586      * Next push static data.  This must happen early on, since it's
00587      * not robust against mark stack overflow.
00588      */
00589      /* Reregister dynamic libraries, in case one got added.          */
00590      /* There is some argument for doing this as late as possible,    */
00591      /* especially on win32, where it can change asynchronously.      */
00592      /* In those cases, we do it here.  But on other platforms, it's  */
00593      /* not safe with the world stopped, so we do it earlier.         */
00594 #      if !defined(REGISTER_LIBRARIES_EARLY)
00595          GC_cond_register_dynamic_libraries();
00596 #      endif
00597 
00598      /* Mark everything in static data areas                             */
00599        for (i = 0; i < n_root_sets; i++) {
00600          GC_push_conditional_with_exclusions(
00601                           GC_static_roots[i].r_start,
00602                           GC_static_roots[i].r_end, all);
00603        }
00604 
00605      /* Mark all free list header blocks, if those were allocated from       */
00606      /* the garbage collected heap.  This makes sure they don't       */
00607      /* disappear if we are not marking from static data.  It also    */
00608      /* saves us the trouble of scanning them, and possibly that of   */
00609      /* marking the freelists.                                        */
00610        for (kind = 0; kind < GC_n_kinds; kind++) {
00611         GC_PTR base = GC_base(GC_obj_kinds[kind].ok_freelist);
00612         if (0 != base) {
00613           GC_set_mark_bit(base);
00614         }
00615        }
00616        
00617      /* Mark from GC internal roots if those might otherwise have     */
00618      /* been excluded.                                                */
00619        if (GC_no_dls || roots_were_cleared) {
00620           GC_push_gc_structures();
00621        }
00622 
00623      /* Mark thread local free lists, even if their mark       */
00624      /* descriptor excludes the link field.                    */
00625      /* If the world is not stopped, this is unsafe.  It is    */
00626      /* also unnecessary, since we will do this again with the */
00627      /* world stopped.                                         */
00628 #      ifdef THREAD_LOCAL_ALLOC
00629          if (GC_world_stopped) GC_mark_thread_local_free_lists();
00630 #      endif
00631 
00632     /*
00633      * Now traverse stacks, and mark from register contents.
00634      * These must be done last, since they can legitimately overflow
00635      * the mark stack.
00636      */
00637 #   ifdef USE_GENERIC_PUSH_REGS
00638        GC_generic_push_regs(cold_gc_frame);
00639        /* Also pushes stack, so that we catch callee-save registers   */
00640        /* saved inside the GC_push_regs frame.                        */
00641 #   else
00642        /*
00643         * push registers - i.e., call GC_push_one(r) for each
00644         * register contents r.
00645         */
00646         GC_push_regs(); /* usually defined in machine_dep.c */
00647        GC_push_current_stack(cold_gc_frame);
00648        /* In the threads case, this only pushes collector frames.      */
00649        /* In the case of linux threads on IA64, the hot section of    */
00650        /* the main stack is marked here, but the register stack       */
00651        /* backing store is handled in the threads-specific code.      */
00652 #   endif
00653     if (GC_push_other_roots != 0) (*GC_push_other_roots)();
00654        /* In the threads case, this also pushes thread stacks. */
00655         /* Note that without interior pointer recognition lots */
00656        /* of stuff may have been pushed already, and this      */
00657        /* should be careful about mark stack overflows. */
00658     /* PLTSCHEME: hook for last roots; need to mark copies of the stack */
00659     if (GC_push_last_roots != 0) (*GC_push_last_roots)();
00660 }
00661 
00662 
00663 /* PLTSCHEME */
00664 void GC_flush_mark_stack()
00665 {
00666   while (!GC_mark_stack_empty()) GC_mark_from_mark_stack();
00667 }
00668