root/gc/mark_rts.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. GC_print_static_roots
  2. GC_is_static_root
  3. rt_hash
  4. GC_roots_present
  5. add_roots_to_index
  6. GC_add_roots
  7. GC_add_roots_inner
  8. GC_PROTO
  9. GC_remove_root_at_pos
  10. GC_rebuild_root_index
  11. GC_remove_tmp_roots
  12. GC_remove_roots
  13. GC_remove_roots_inner
  14. GC_is_tmp_root
  15. GC_approx_sp
  16. GC_next_exclusion
  17. GC_exclude_static_roots
  18. GC_push_conditional_with_exclusions
  19. GC_push_current_stack
  20. GC_PROTO
  21. GC_cond_register_dynamic_libraries
  22. GC_push_roots

   1 /* 
   2  * Copyright 1988, 1989 Hans-J. Boehm, Alan J. Demers
   3  * Copyright (c) 1991-1994 by Xerox Corporation.  All rights reserved.
   4  *
   5  * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
   6  * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
   7  *
   8  * Permission is hereby granted to use or copy this program
   9  * for any purpose,  provided the above notices are retained on all copies.
  10  * Permission to modify the code and to distribute modified code is granted,
  11  * provided the above notices are retained, and a notice that the code was
  12  * modified is included with the above copyright notice.
  13  */
  14 # include <stdio.h>
  15 # include "private/gc_priv.h"
  16 
  17 /* Data structure for list of root sets.                                */
  18 /* We keep a hash table, so that we can filter out duplicate additions. */
  19 /* Under Win32, we need to do a better job of filtering overlaps, so    */
  20 /* we resort to sequential search, and pay the price.                   */
  21 /* This is really declared in gc_priv.h:
  22 struct roots {
  23         ptr_t r_start;
  24         ptr_t r_end;
  25  #      if !defined(MSWIN32) && !defined(MSWINCE)
  26           struct roots * r_next;
  27  #      endif
  28         GC_bool r_tmp;
  29                 -- Delete before registering new dynamic libraries
  30 };
  31 
  32 struct roots GC_static_roots[MAX_ROOT_SETS];
  33 */
  34 
  35 int GC_no_dls = 0;      /* Register dynamic library data segments.      */
  36 
  37 static int n_root_sets = 0;
  38 
  39         /* GC_static_roots[0..n_root_sets) contains the valid root sets. */
  40 
  41 # if !defined(NO_DEBUGGING)
  42 /* For debugging:       */
  43 void GC_print_static_roots()
  44 {
  45     register int i;
  46     size_t total = 0;
  47     
  48     for (i = 0; i < n_root_sets; i++) {
  49         GC_printf2("From 0x%lx to 0x%lx ",
  50                    (unsigned long) GC_static_roots[i].r_start,
  51                    (unsigned long) GC_static_roots[i].r_end);
  52         if (GC_static_roots[i].r_tmp) {
  53             GC_printf0(" (temporary)\n");
  54         } else {
  55             GC_printf0("\n");
  56         }
  57         total += GC_static_roots[i].r_end - GC_static_roots[i].r_start;
  58     }
  59     GC_printf1("Total size: %ld\n", (unsigned long) total);
  60     if (GC_root_size != total) {
  61         GC_printf1("GC_root_size incorrect: %ld!!\n",
  62                    (unsigned long) GC_root_size);
  63     }
  64 }
  65 # endif /* NO_DEBUGGING */
  66 
  67 /* Primarily for debugging support:     */
  68 /* Is the address p in one of the registered static                     */
  69 /* root sections?                                                       */
  70 GC_bool GC_is_static_root(p)
  71 ptr_t p;
  72 {
  73     static int last_root_set = MAX_ROOT_SETS;
  74     register int i;
  75     
  76     
  77     if (last_root_set < n_root_sets
  78         && p >= GC_static_roots[last_root_set].r_start
  79         && p < GC_static_roots[last_root_set].r_end) return(TRUE);
  80     for (i = 0; i < n_root_sets; i++) {
  81         if (p >= GC_static_roots[i].r_start
  82             && p < GC_static_roots[i].r_end) {
  83             last_root_set = i;
  84             return(TRUE);
  85         }
  86     }
  87     return(FALSE);
  88 }
  89 
  90 #if !defined(MSWIN32) && !defined(MSWINCE)
  91 /* 
  92 #   define LOG_RT_SIZE 6
  93 #   define RT_SIZE (1 << LOG_RT_SIZE)  -- Power of 2, may be != MAX_ROOT_SETS
  94 
  95     struct roots * GC_root_index[RT_SIZE];
  96         -- Hash table header.  Used only to check whether a range is
  97         -- already present.
  98         -- really defined in gc_priv.h
  99 */
 100 
 101 static int rt_hash(addr)
 102 char * addr;
 103 {
 104     word result = (word) addr;
 105 #   if CPP_WORDSZ > 8*LOG_RT_SIZE
 106         result ^= result >> 8*LOG_RT_SIZE;
 107 #   endif
 108 #   if CPP_WORDSZ > 4*LOG_RT_SIZE
 109         result ^= result >> 4*LOG_RT_SIZE;
 110 #   endif
 111     result ^= result >> 2*LOG_RT_SIZE;
 112     result ^= result >> LOG_RT_SIZE;
 113     result &= (RT_SIZE-1);
 114     return(result);
 115 }
 116 
 117 /* Is a range starting at b already in the table? If so return a        */
 118 /* pointer to it, else NIL.                                             */
 119 struct roots * GC_roots_present(b)
 120 char *b;
 121 {
 122     register int h = rt_hash(b);
 123     register struct roots *p = GC_root_index[h];
 124     
 125     while (p != 0) {
 126         if (p -> r_start == (ptr_t)b) return(p);
 127         p = p -> r_next;
 128     }
 129     return(FALSE);
 130 }
 131 
 132 /* Add the given root structure to the index. */
 133 static void add_roots_to_index(p)
 134 struct roots *p;
 135 {
 136     register int h = rt_hash(p -> r_start);
 137     
 138     p -> r_next = GC_root_index[h];
 139     GC_root_index[h] = p;
 140 }
 141 
 142 # else /* MSWIN32 || MSWINCE */
 143 
 144 #   define add_roots_to_index(p)
 145 
 146 # endif
 147 
 148 
 149 
 150 
 151 word GC_root_size = 0;
 152 
 153 void GC_add_roots(b, e)
 154 char * b; char * e;
 155 {
 156     DCL_LOCK_STATE;
 157     
 158     DISABLE_SIGNALS();
 159     LOCK();
 160     GC_add_roots_inner(b, e, FALSE);
 161     UNLOCK();
 162     ENABLE_SIGNALS();
 163 }
 164 
 165 
 166 /* Add [b,e) to the root set.  Adding the same interval a second time   */
 167 /* is a moderately fast noop, and hence benign.  We do not handle       */
 168 /* different but overlapping intervals efficiently.  (We do handle      */
 169 /* them correctly.)                                                     */
 170 /* Tmp specifies that the interval may be deleted before                */
 171 /* reregistering dynamic libraries.                                     */ 
 172 void GC_add_roots_inner(b, e, tmp)
 173 char * b; char * e;
 174 GC_bool tmp;
 175 {
 176     struct roots * old;
 177     
 178 #   if defined(MSWIN32) || defined(MSWINCE)
 179       /* Spend the time to ensure that there are no overlapping */
 180       /* or adjacent intervals.                                 */
 181       /* This could be done faster with e.g. a                  */
 182       /* balanced tree.  But the execution time here is         */
 183       /* virtually guaranteed to be dominated by the time it    */
 184       /* takes to scan the roots.                               */
 185       {
 186         register int i;
 187         
 188         for (i = 0; i < n_root_sets; i++) {
 189             old = GC_static_roots + i;
 190             if ((ptr_t)b <= old -> r_end && (ptr_t)e >= old -> r_start) {
 191                 if ((ptr_t)b < old -> r_start) {
 192                     old -> r_start = (ptr_t)b;
 193                     GC_root_size += (old -> r_start - (ptr_t)b);
 194                 }
 195                 if ((ptr_t)e > old -> r_end) {
 196                     old -> r_end = (ptr_t)e;
 197                     GC_root_size += ((ptr_t)e - old -> r_end);
 198                 }
 199                 old -> r_tmp &= tmp;
 200                 break;
 201             }
 202         }
 203         if (i < n_root_sets) {
 204           /* merge other overlapping intervals */
 205             struct roots *other;
 206             
 207             for (i++; i < n_root_sets; i++) {
 208               other = GC_static_roots + i;
 209               b = (char *)(other -> r_start);
 210               e = (char *)(other -> r_end);
 211               if ((ptr_t)b <= old -> r_end && (ptr_t)e >= old -> r_start) {
 212                 if ((ptr_t)b < old -> r_start) {
 213                     old -> r_start = (ptr_t)b;
 214                     GC_root_size += (old -> r_start - (ptr_t)b);
 215                 }
 216                 if ((ptr_t)e > old -> r_end) {
 217                     old -> r_end = (ptr_t)e;
 218                     GC_root_size += ((ptr_t)e - old -> r_end);
 219                 }
 220                 old -> r_tmp &= other -> r_tmp;
 221                 /* Delete this entry. */
 222                   GC_root_size -= (other -> r_end - other -> r_start);
 223                   other -> r_start = GC_static_roots[n_root_sets-1].r_start;
 224                   other -> r_end = GC_static_roots[n_root_sets-1].r_end;
 225                                   n_root_sets--;
 226               }
 227             }
 228           return;
 229         }
 230       }
 231 #   else
 232       old = GC_roots_present(b);
 233       if (old != 0) {
 234         if ((ptr_t)e <= old -> r_end) /* already there */ return;
 235         /* else extend */
 236         GC_root_size += (ptr_t)e - old -> r_end;
 237         old -> r_end = (ptr_t)e;
 238         return;
 239       }
 240 #   endif
 241     if (n_root_sets == MAX_ROOT_SETS) {
 242         ABORT("Too many root sets\n");
 243     }
 244     GC_static_roots[n_root_sets].r_start = (ptr_t)b;
 245     GC_static_roots[n_root_sets].r_end = (ptr_t)e;
 246     GC_static_roots[n_root_sets].r_tmp = tmp;
 247 #   if !defined(MSWIN32) && !defined(MSWINCE)
 248       GC_static_roots[n_root_sets].r_next = 0;
 249 #   endif
 250     add_roots_to_index(GC_static_roots + n_root_sets);
 251     GC_root_size += (ptr_t)e - (ptr_t)b;
 252     n_root_sets++;
 253 }
 254 
 255 static GC_bool roots_were_cleared = FALSE;
 256 
 257 void GC_clear_roots GC_PROTO((void))
 258 {
 259     DCL_LOCK_STATE;
 260     
 261     DISABLE_SIGNALS();
 262     LOCK();
 263     roots_were_cleared = TRUE;
 264     n_root_sets = 0;
 265     GC_root_size = 0;
 266 #   if !defined(MSWIN32) && !defined(MSWINCE)
 267     {
 268         register int i;
 269         
 270         for (i = 0; i < RT_SIZE; i++) GC_root_index[i] = 0;
 271     }
 272 #   endif
 273     UNLOCK();
 274     ENABLE_SIGNALS();
 275 }
 276 
 277 /* Internal use only; lock held.        */
 278 static void GC_remove_root_at_pos(i) 
 279 int i;
 280 {
 281     GC_root_size -= (GC_static_roots[i].r_end - GC_static_roots[i].r_start);
 282     GC_static_roots[i].r_start = GC_static_roots[n_root_sets-1].r_start;
 283     GC_static_roots[i].r_end = GC_static_roots[n_root_sets-1].r_end;
 284     GC_static_roots[i].r_tmp = GC_static_roots[n_root_sets-1].r_tmp;
 285     n_root_sets--;
 286 }
 287 
 288 #if !defined(MSWIN32) && !defined(MSWINCE)
 289 static void GC_rebuild_root_index()
 290 {
 291     register int i;
 292         
 293     for (i = 0; i < RT_SIZE; i++) GC_root_index[i] = 0;
 294     for (i = 0; i < n_root_sets; i++)
 295         add_roots_to_index(GC_static_roots + i);
 296 }
 297 #endif
 298 
 299 /* Internal use only; lock held.        */
 300 void GC_remove_tmp_roots()
 301 {
 302     register int i;
 303     
 304     for (i = 0; i < n_root_sets; ) {
 305         if (GC_static_roots[i].r_tmp) {
 306             GC_remove_root_at_pos(i);
 307         } else {
 308             i++;
 309     }
 310     }
 311     #if !defined(MSWIN32) && !defined(MSWINCE)
 312     GC_rebuild_root_index();
 313     #endif
 314 }
 315 
 316 #if !defined(MSWIN32) && !defined(MSWINCE)
 317 void GC_remove_roots(b, e)
 318 char * b; char * e;
 319 {
 320     DCL_LOCK_STATE;
 321     
 322     DISABLE_SIGNALS();
 323     LOCK();
 324     GC_remove_roots_inner(b, e);
 325     UNLOCK();
 326     ENABLE_SIGNALS();
 327 }
 328 
 329 /* Should only be called when the lock is held */
 330 void GC_remove_roots_inner(b,e)
 331 char * b; char * e;
 332 {
 333     int i;
 334     for (i = 0; i < n_root_sets; ) {
 335         if (GC_static_roots[i].r_start >= (ptr_t)b && GC_static_roots[i].r_end <= (ptr_t)e) {
 336             GC_remove_root_at_pos(i);
 337         } else {
 338             i++;
 339         }
 340     }
 341     GC_rebuild_root_index();
 342 }
 343 #endif /* !defined(MSWIN32) && !defined(MSWINCE) */
 344 
 345 #if defined(MSWIN32) || defined(_WIN32_WCE_EMULATION)
 346 /* Workaround for the OS mapping and unmapping behind our back:         */
 347 /* Is the address p in one of the temporary static root sections?       */
 348 GC_bool GC_is_tmp_root(p)
 349 ptr_t p;
 350 {
 351     static int last_root_set = MAX_ROOT_SETS;
 352     register int i;
 353     
 354     if (last_root_set < n_root_sets
 355         && p >= GC_static_roots[last_root_set].r_start
 356         && p < GC_static_roots[last_root_set].r_end)
 357         return GC_static_roots[last_root_set].r_tmp;
 358     for (i = 0; i < n_root_sets; i++) {
 359         if (p >= GC_static_roots[i].r_start
 360             && p < GC_static_roots[i].r_end) {
 361             last_root_set = i;
 362             return GC_static_roots[i].r_tmp;
 363         }
 364     }
 365     return(FALSE);
 366 }
 367 #endif /* MSWIN32 || _WIN32_WCE_EMULATION */
 368 
 369 ptr_t GC_approx_sp()
 370 {
 371     VOLATILE word dummy;
 372 
 373     dummy = 42; /* Force stack to grow if necessary.    Otherwise the   */
 374                 /* later accesses might cause the kernel to think we're */
 375                 /* doing something wrong.                               */
 376 #   ifdef _MSC_VER
 377 #     pragma warning(disable:4172)
 378 #   endif
 379     return((ptr_t)(&dummy));
 380 #   ifdef _MSC_VER
 381 #     pragma warning(default:4172)
 382 #   endif
 383 }
 384 
 385 /*
 386  * Data structure for excluded static roots.
 387  * Real declaration is in gc_priv.h.
 388 
 389 struct exclusion {
 390     ptr_t e_start;
 391     ptr_t e_end;
 392 };
 393 
 394 struct exclusion GC_excl_table[MAX_EXCLUSIONS];
 395                                         -- Array of exclusions, ascending
 396                                         -- address order.
 397 */
 398 
 399 size_t GC_excl_table_entries = 0;       /* Number of entries in use.      */
 400 
 401 /* Return the first exclusion range that includes an address >= start_addr */
 402 /* Assumes the exclusion table contains at least one entry (namely the     */
 403 /* GC data structures).                                                    */
 404 struct exclusion * GC_next_exclusion(start_addr)
 405 ptr_t start_addr;
 406 {
 407     size_t low = 0;
 408     size_t high = GC_excl_table_entries - 1;
 409     size_t mid;
 410 
 411     while (high > low) {
 412         mid = (low + high) >> 1;
 413         /* low <= mid < high    */
 414         if ((word) GC_excl_table[mid].e_end <= (word) start_addr) {
 415             low = mid + 1;
 416         } else {
 417             high = mid;
 418         }
 419     }
 420     if ((word) GC_excl_table[low].e_end <= (word) start_addr) return 0;
 421     return GC_excl_table + low;
 422 }
 423 
 424 void GC_exclude_static_roots(start, finish)
 425 GC_PTR start;
 426 GC_PTR finish;
 427 {
 428     struct exclusion * next;
 429     size_t next_index, i;
 430 
 431     if (0 == GC_excl_table_entries) {
 432         next = 0;
 433     } else {
 434         next = GC_next_exclusion(start);
 435     }
 436     if (0 != next) {
 437       if ((word)(next -> e_start) < (word) finish) {
 438         /* incomplete error check. */
 439         ABORT("exclusion ranges overlap");
 440       }  
 441       if ((word)(next -> e_start) == (word) finish) {
 442         /* extend old range backwards   */
 443           next -> e_start = (ptr_t)start;
 444           return;
 445       }
 446       next_index = next - GC_excl_table;
 447       for (i = GC_excl_table_entries; i > next_index; --i) {
 448         GC_excl_table[i] = GC_excl_table[i-1];
 449       }
 450     } else {
 451       next_index = GC_excl_table_entries;
 452     }
 453     if (GC_excl_table_entries == MAX_EXCLUSIONS) ABORT("Too many exclusions");
 454     GC_excl_table[next_index].e_start = (ptr_t)start;
 455     GC_excl_table[next_index].e_end = (ptr_t)finish;
 456     ++GC_excl_table_entries;
 457 }
 458 
 459 /* Invoke push_conditional on ranges that are not excluded. */
 460 void GC_push_conditional_with_exclusions(bottom, top, all)
 461 ptr_t bottom;
 462 ptr_t top;
 463 int all;
 464 {
 465     struct exclusion * next;
 466     ptr_t excl_start;
 467 
 468     while (bottom < top) {
 469         next = GC_next_exclusion(bottom);
 470         if (0 == next || (excl_start = next -> e_start) >= top) {
 471             GC_push_conditional(bottom, top, all);
 472             return;
 473         }
 474         if (excl_start > bottom) GC_push_conditional(bottom, excl_start, all);
 475         bottom = next -> e_end;
 476     }
 477 }
 478 
 479 /*
 480  * In the absence of threads, push the stack contents.
 481  * In the presence of threads, push enough of the current stack
 482  * to ensure that callee-save registers saved in collector frames have been
 483  * seen.
 484  */
 485 void GC_push_current_stack(cold_gc_frame)
 486 ptr_t cold_gc_frame;
 487 {
 488 #   if defined(THREADS)
 489         if (0 == cold_gc_frame) return;
 490 #       ifdef STACK_GROWS_DOWN
 491           GC_push_all_eager(GC_approx_sp(), cold_gc_frame);
 492           /* For IA64, the register stack backing store is handled      */
 493           /* in the thread-specific code.                               */
 494 #       else
 495           GC_push_all_eager( cold_gc_frame, GC_approx_sp() );
 496 #       endif
 497 #   else
 498 #       ifdef STACK_GROWS_DOWN
 499             GC_push_all_stack_partially_eager( GC_approx_sp(), GC_stackbottom,
 500                                                cold_gc_frame );
 501 #           ifdef IA64
 502               /* We also need to push the register stack backing store. */
 503               /* This should really be done in the same way as the      */
 504               /* regular stack.  For now we fudge it a bit.             */
 505               /* Note that the backing store grows up, so we can't use  */
 506               /* GC_push_all_stack_partially_eager.                     */
 507               {
 508                 extern word GC_save_regs_ret_val;
 509                         /* Previously set to backing store pointer.     */
 510                 ptr_t bsp = (ptr_t) GC_save_regs_ret_val;
 511                 ptr_t cold_gc_bs_pointer;
 512                 if (GC_all_interior_pointers) {
 513                   cold_gc_bs_pointer = bsp - 2048;
 514                   if (cold_gc_bs_pointer < BACKING_STORE_BASE) {
 515                     cold_gc_bs_pointer = BACKING_STORE_BASE;
 516                   } else {
 517                     GC_push_all_stack(BACKING_STORE_BASE, cold_gc_bs_pointer);
 518                   }
 519                 } else {
 520                   cold_gc_bs_pointer = BACKING_STORE_BASE;
 521                 }
 522                 GC_push_all_eager(cold_gc_bs_pointer, bsp);
 523                 /* All values should be sufficiently aligned that we    */
 524                 /* dont have to worry about the boundary.               */
 525               }
 526 #           endif
 527 #       else
 528             GC_push_all_stack_partially_eager( GC_stackbottom, GC_approx_sp(),
 529                                                cold_gc_frame );
 530 #       endif
 531 #   endif /* !THREADS */
 532 }
 533 
 534 /*
 535  * Push GC internal roots.  Only called if there is some reason to believe
 536  * these would not otherwise get registered.
 537  */
 538 void GC_push_gc_structures GC_PROTO((void))
 539 {
 540     GC_push_finalizer_structures();
 541     GC_push_stubborn_structures();
 542 #   if defined(THREADS)
 543       GC_push_thread_structures();
 544 #   endif
 545 }
 546 
 547 #ifdef THREAD_LOCAL_ALLOC
 548   void GC_mark_thread_local_free_lists();
 549 #endif
 550 
 551 void GC_cond_register_dynamic_libraries()
 552 {
 553 # if (defined(DYNAMIC_LOADING) || defined(MSWIN32) || defined(MSWINCE) \
 554      || defined(PCR)) && !defined(SRC_M3)
 555     GC_remove_tmp_roots();
 556     if (!GC_no_dls) GC_register_dynamic_libraries();
 557 # else
 558     GC_no_dls = TRUE;
 559 # endif
 560 }
 561 
 562 /*
 563  * Call the mark routines (GC_tl_push for a single pointer, GC_push_conditional
 564  * on groups of pointers) on every top level accessible pointer.
 565  * If all is FALSE, arrange to push only possibly altered values.
 566  * Cold_gc_frame is an address inside a GC frame that
 567  * remains valid until all marking is complete.
 568  * A zero value indicates that it's OK to miss some
 569  * register values.
 570  */
 571 void GC_push_roots(all, cold_gc_frame)
 572 GC_bool all;
 573 ptr_t cold_gc_frame;
 574 {
 575     int i;
 576     int kind;
 577 
 578     /*
 579      * Next push static data.  This must happen early on, since it's
 580      * not robust against mark stack overflow.
 581      */
 582      /* Reregister dynamic libraries, in case one got added.            */
 583      /* There is some argument for doing this as late as possible,      */
 584      /* especially on win32, where it can change asynchronously.        */
 585      /* In those cases, we do it here.  But on other platforms, it's    */
 586      /* not safe with the world stopped, so we do it earlier.           */
 587 #      if !defined(REGISTER_LIBRARIES_EARLY)
 588          GC_cond_register_dynamic_libraries();
 589 #      endif
 590 
 591      /* Mark everything in static data areas                             */
 592        for (i = 0; i < n_root_sets; i++) {
 593          GC_push_conditional_with_exclusions(
 594                              GC_static_roots[i].r_start,
 595                              GC_static_roots[i].r_end, all);
 596        }
 597 
 598      /* Mark all free list header blocks, if those were allocated from  */
 599      /* the garbage collected heap.  This makes sure they don't         */
 600      /* disappear if we are not marking from static data.  It also      */
 601      /* saves us the trouble of scanning them, and possibly that of     */
 602      /* marking the freelists.                                          */
 603        for (kind = 0; kind < GC_n_kinds; kind++) {
 604          GC_PTR base = GC_base(GC_obj_kinds[kind].ok_freelist);
 605          if (0 != base) {
 606            GC_set_mark_bit(base);
 607          }
 608        }
 609        
 610      /* Mark from GC internal roots if those might otherwise have       */
 611      /* been excluded.                                                  */
 612        if (GC_no_dls || roots_were_cleared) {
 613            GC_push_gc_structures();
 614        }
 615 
 616      /* Mark thread local free lists, even if their mark        */
 617      /* descriptor excludes the link field.                     */
 618      /* If the world is not stopped, this is unsafe.  It is     */
 619      /* also unnecessary, since we will do this again with the  */
 620      /* world stopped.                                          */
 621 #      ifdef THREAD_LOCAL_ALLOC
 622          if (GC_world_stopped) GC_mark_thread_local_free_lists();
 623 #      endif
 624 
 625     /*
 626      * Now traverse stacks, and mark from register contents.
 627      * These must be done last, since they can legitimately overflow
 628      * the mark stack.
 629      */
 630 #   ifdef USE_GENERIC_PUSH_REGS
 631         GC_generic_push_regs(cold_gc_frame);
 632         /* Also pushes stack, so that we catch callee-save registers    */
 633         /* saved inside the GC_push_regs frame.                         */
 634 #   else
 635        /*
 636         * push registers - i.e., call GC_push_one(r) for each
 637         * register contents r.
 638         */
 639         GC_push_regs(); /* usually defined in machine_dep.c */
 640         GC_push_current_stack(cold_gc_frame);
 641         /* In the threads case, this only pushes collector frames.      */
 642         /* In the case of linux threads on IA64, the hot section of     */
 643         /* the main stack is marked here, but the register stack        */
 644         /* backing store is handled in the threads-specific code.       */
 645 #   endif
 646     if (GC_push_other_roots != 0) (*GC_push_other_roots)();
 647         /* In the threads case, this also pushes thread stacks. */
 648         /* Note that without interior pointer recognition lots  */
 649         /* of stuff may have been pushed already, and this      */
 650         /* should be careful about mark stack overflows.        */
 651 }
 652 

/* [<][>][^][v][top][bottom][index][help] */