~ubuntu-branches/ubuntu/quantal/libgc/quantal

« back to all changes in this revision

Viewing changes to mark.c

  • Committer: Bazaar Package Importer
  • Author(s): Christoph Egger
  • Date: 2011-02-19 12:19:56 UTC
  • mfrom: (1.3.2 upstream) (0.1.5 experimental)
  • mto: This revision was merged to the branch mainline in revision 14.
  • Revision ID: james.westby@ubuntu.com-20110219121956-67rb69xlt5nud3v2
Tags: 1:7.1-5
Upload to unstable

Show diffs side-by-side

added added

removed removed

Lines of Context:
32
32
#endif
33
33
 
34
34
/* Single argument version, robust against whole program analysis. */
35
 
void GC_noop1(x)
36
 
word x;
 
35
void GC_noop1(word x)
37
36
{
38
 
    static VOLATILE word sink;
 
37
    static volatile word sink;
39
38
 
40
39
    sink = x;
41
40
}
42
41
 
43
42
/* mark_proc GC_mark_procs[MAX_MARK_PROCS] = {0} -- declared in gc_priv.h */
44
43
 
45
 
word GC_n_mark_procs = GC_RESERVED_MARK_PROCS;
 
44
unsigned GC_n_mark_procs = GC_RESERVED_MARK_PROCS;
46
45
 
47
46
/* Initialize GC_obj_kinds properly and standard free lists properly.   */
48
47
/* This must be done statically since they may be accessed before       */
70
69
 
71
70
# ifdef ATOMIC_UNCOLLECTABLE
72
71
#   ifdef STUBBORN_ALLOC
73
 
      int GC_n_kinds = 5;
 
72
      unsigned GC_n_kinds = 5;
74
73
#   else
75
 
      int GC_n_kinds = 4;
 
74
      unsigned GC_n_kinds = 4;
76
75
#   endif
77
76
# else
78
77
#   ifdef STUBBORN_ALLOC
79
 
      int GC_n_kinds = 4;
 
78
      unsigned GC_n_kinds = 4;
80
79
#   else
81
 
      int GC_n_kinds = 3;
 
80
      unsigned GC_n_kinds = 3;
82
81
#   endif
83
82
# endif
84
83
 
106
105
 
107
106
mse * GC_mark_stack_limit;
108
107
 
109
 
word GC_mark_stack_size = 0;
 
108
size_t GC_mark_stack_size = 0;
110
109
 
111
110
#ifdef PARALLEL_MARK
112
 
  mse * VOLATILE GC_mark_stack_top;
 
111
# include "atomic_ops.h"
 
112
 
 
113
  mse * volatile GC_mark_stack_top;
 
114
  /* Updated only with mark lock held, but read asynchronously. */
 
115
  volatile AO_t GC_first_nonempty;
 
116
        /* Lowest entry on mark stack   */
 
117
        /* that may be nonempty.        */
 
118
        /* Updated only by initiating   */
 
119
        /* thread.                      */
113
120
#else
114
121
  mse * GC_mark_stack_top;
115
122
#endif
126
133
/* Is a collection in progress?  Note that this can return true in the  */
127
134
/* nonincremental case, if a collection has been abandoned and the      */
128
135
/* mark state is now MS_INVALID.                                        */
129
 
GC_bool GC_collection_in_progress()
 
136
GC_bool GC_collection_in_progress(void)
130
137
{
131
138
    return(GC_mark_state != MS_NONE);
132
139
}
133
140
 
134
141
/* clear all mark bits in the header */
135
 
void GC_clear_hdr_marks(hhdr)
136
 
register hdr * hhdr;
 
142
void GC_clear_hdr_marks(hdr *hhdr)
137
143
{
 
144
    size_t last_bit = FINAL_MARK_BIT(hhdr -> hb_sz);
 
145
 
138
146
#   ifdef USE_MARK_BYTES
139
147
      BZERO(hhdr -> hb_marks, MARK_BITS_SZ);
 
148
      hhdr -> hb_marks[last_bit] = 1;
140
149
#   else
141
150
      BZERO(hhdr -> hb_marks, MARK_BITS_SZ*sizeof(word));
 
151
      set_mark_bit_from_hdr(hhdr, last_bit);
142
152
#   endif
 
153
    hhdr -> hb_n_marks = 0;
143
154
}
144
155
 
145
156
/* Set all mark bits in the header.  Used for uncollectable blocks. */
146
 
void GC_set_hdr_marks(hhdr)
147
 
register hdr * hhdr;
 
157
void GC_set_hdr_marks(hdr *hhdr)
148
158
{
149
 
    register int i;
 
159
    unsigned i;
 
160
    size_t sz = hhdr -> hb_sz;
 
161
    size_t n_marks = FINAL_MARK_BIT(sz);
150
162
 
151
 
    for (i = 0; i < MARK_BITS_SZ; ++i) {
152
 
#     ifdef USE_MARK_BYTES
 
163
#   ifdef USE_MARK_BYTES
 
164
      for (i = 0; i <= n_marks; i += MARK_BIT_OFFSET(sz)) {
153
165
        hhdr -> hb_marks[i] = 1;
154
 
#     else
 
166
      }
 
167
#   else
 
168
      for (i = 0; i < divWORDSZ(n_marks + WORDSZ); ++i) {
155
169
        hhdr -> hb_marks[i] = ONES;
156
 
#     endif
157
 
    }
 
170
      }
 
171
#   endif
 
172
#   ifdef MARK_BIT_PER_OBJ
 
173
      hhdr -> hb_n_marks = n_marks - 1;
 
174
#   else
 
175
      hhdr -> hb_n_marks = HBLK_OBJS(sz);
 
176
#   endif
158
177
}
159
178
 
160
179
/*
161
180
 * Clear all mark bits associated with block h.
162
181
 */
163
182
/*ARGSUSED*/
164
 
# if defined(__STDC__) || defined(__cplusplus)
165
 
    static void clear_marks_for_block(struct hblk *h, word dummy)
166
 
# else
167
 
    static void clear_marks_for_block(h, dummy)
168
 
    struct hblk *h;
169
 
    word dummy;
170
 
# endif
 
183
static void clear_marks_for_block(struct hblk *h, word dummy)
171
184
{
172
185
    register hdr * hhdr = HDR(h);
173
186
    
179
192
}
180
193
 
181
194
/* Slow but general routines for setting/clearing/asking about mark bits */
182
 
void GC_set_mark_bit(p)
183
 
ptr_t p;
184
 
{
185
 
    register struct hblk *h = HBLKPTR(p);
186
 
    register hdr * hhdr = HDR(h);
187
 
    register int word_no = (word *)p - (word *)h;
188
 
    
189
 
    set_mark_bit_from_hdr(hhdr, word_no);
190
 
}
191
 
 
192
 
void GC_clear_mark_bit(p)
193
 
ptr_t p;
194
 
{
195
 
    register struct hblk *h = HBLKPTR(p);
196
 
    register hdr * hhdr = HDR(h);
197
 
    register int word_no = (word *)p - (word *)h;
198
 
    
199
 
    clear_mark_bit_from_hdr(hhdr, word_no);
200
 
}
201
 
 
202
 
GC_bool GC_is_marked(p)
203
 
ptr_t p;
204
 
{
205
 
    register struct hblk *h = HBLKPTR(p);
206
 
    register hdr * hhdr = HDR(h);
207
 
    register int word_no = (word *)p - (word *)h;
208
 
    
209
 
    return(mark_bit_from_hdr(hhdr, word_no));
 
195
void GC_set_mark_bit(ptr_t p)
 
196
{
 
197
    struct hblk *h = HBLKPTR(p);
 
198
    hdr * hhdr = HDR(h);
 
199
    word bit_no = MARK_BIT_NO(p - (ptr_t)h, hhdr -> hb_sz);
 
200
    
 
201
    if (!mark_bit_from_hdr(hhdr, bit_no)) {
 
202
      set_mark_bit_from_hdr(hhdr, bit_no);
 
203
      ++hhdr -> hb_n_marks;
 
204
    }
 
205
}
 
206
 
 
207
void GC_clear_mark_bit(ptr_t p)
 
208
{
 
209
    struct hblk *h = HBLKPTR(p);
 
210
    hdr * hhdr = HDR(h);
 
211
    word bit_no = MARK_BIT_NO(p - (ptr_t)h, hhdr -> hb_sz);
 
212
    
 
213
    if (mark_bit_from_hdr(hhdr, bit_no)) {
 
214
      size_t n_marks;
 
215
      clear_mark_bit_from_hdr(hhdr, bit_no);
 
216
      n_marks = hhdr -> hb_n_marks - 1;
 
217
#     ifdef PARALLEL_MARK
 
218
        if (n_marks != 0)
 
219
          hhdr -> hb_n_marks = n_marks; 
 
220
        /* Don't decrement to zero.  The counts are approximate due to  */
 
221
        /* concurrency issues, but we need to ensure that a count of    */
 
222
        /* zero implies an empty block.                                 */
 
223
#     else
 
224
          hhdr -> hb_n_marks = n_marks; 
 
225
#     endif
 
226
    }
 
227
}
 
228
 
 
229
GC_bool GC_is_marked(ptr_t p)
 
230
{
 
231
    struct hblk *h = HBLKPTR(p);
 
232
    hdr * hhdr = HDR(h);
 
233
    word bit_no = MARK_BIT_NO(p - (ptr_t)h, hhdr -> hb_sz);
 
234
    
 
235
    return((GC_bool)mark_bit_from_hdr(hhdr, bit_no));
210
236
}
211
237
 
212
238
 
215
241
 * the marker invariant, and sets GC_mark_state to reflect this.
216
242
 * (This implicitly starts marking to reestablish the invariant.)
217
243
 */
218
 
void GC_clear_marks()
 
244
void GC_clear_marks(void)
219
245
{
220
246
    GC_apply_to_all_blocks(clear_marks_for_block, (word)0);
221
247
    GC_objects_are_marked = FALSE;
222
248
    GC_mark_state = MS_INVALID;
223
249
    scan_ptr = 0;
224
 
#   ifdef GATHERSTATS
225
 
        /* Counters reflect currently marked objects: reset here */
226
 
        GC_composite_in_use = 0;
227
 
        GC_atomic_in_use = 0;
228
 
#   endif
229
 
 
230
250
}
231
251
 
232
252
/* Initiate a garbage collection.  Initiates a full collection if the   */
233
253
/* mark state is invalid.                                               */
234
254
/*ARGSUSED*/
235
 
void GC_initiate_gc()
 
255
void GC_initiate_gc(void)
236
256
{
237
257
    if (GC_dirty_maintained) GC_read_dirty();
238
258
#   ifdef STUBBORN_ALLOC
256
276
}
257
277
 
258
278
 
259
 
static void alloc_mark_stack();
 
279
static void alloc_mark_stack(size_t);
 
280
 
 
281
# if defined(MSWIN32) || defined(USE_PROC_FOR_LIBRARIES) && defined(THREADS)
 
282
    /* Under rare conditions, we may end up marking from nonexistent memory. */
 
283
    /* Hence we need to be prepared to recover by running GC_mark_some       */
 
284
    /* with a suitable handler in place.                                     */
 
285
#   define WRAP_MARK_SOME
 
286
# endif
260
287
 
261
288
/* Perform a small amount of marking.                   */
262
289
/* We try to touch roughly a page of memory.            */
267
294
/* register values.                                     */
268
295
/* We hold the allocation lock.  In the case of         */
269
296
/* incremental collection, the world may not be stopped.*/
270
 
#ifdef MSWIN32
 
297
#ifdef WRAP_MARK_SOME
271
298
  /* For win32, this is called after we establish a structured  */
272
299
  /* exception handler, in case Windows unmaps one of our root  */
273
300
  /* segments.  See below.  In either case, we acquire the      */
274
301
  /* allocator lock long before we get here.                    */
275
 
  GC_bool GC_mark_some_inner(cold_gc_frame)
276
 
  ptr_t cold_gc_frame;
 
302
  GC_bool GC_mark_some_inner(ptr_t cold_gc_frame)
277
303
#else
278
 
  GC_bool GC_mark_some(cold_gc_frame)
279
 
  ptr_t cold_gc_frame;
 
304
  GC_bool GC_mark_some(ptr_t cold_gc_frame)
280
305
#endif
281
306
{
282
307
    switch(GC_mark_state) {
295
320
            } else {
296
321
                scan_ptr = GC_push_next_marked_dirty(scan_ptr);
297
322
                if (scan_ptr == 0) {
298
 
#                   ifdef CONDPRINT
299
 
                      if (GC_print_stats) {
300
 
                        GC_printf1("Marked from %lu dirty pages\n",
301
 
                                   (unsigned long)GC_n_rescuing_pages);
302
 
                      }
303
 
#                   endif
 
323
                    if (GC_print_stats) {
 
324
                        GC_log_printf("Marked from %u dirty pages\n",
 
325
                                      GC_n_rescuing_pages);
 
326
                    }
304
327
                    GC_push_roots(FALSE, cold_gc_frame);
305
328
                    GC_objects_are_marked = TRUE;
306
329
                    if (GC_mark_state != MS_INVALID) {
344
367
              /* the allocation lock.                                   */
345
368
                if (GC_parallel) {
346
369
                  GC_do_parallel_mark();
347
 
                  GC_ASSERT(GC_mark_stack_top < GC_first_nonempty);
 
370
                  GC_ASSERT(GC_mark_stack_top < (mse *)GC_first_nonempty);
348
371
                  GC_mark_stack_top = GC_mark_stack - 1;
349
372
                  if (GC_mark_stack_too_small) {
350
373
                    alloc_mark_stack(2*GC_mark_stack_size);
402
425
}
403
426
 
404
427
 
405
 
#ifdef MSWIN32
406
 
 
407
 
# ifdef __GNUC__
 
428
#if defined(MSWIN32) && defined(__GNUC__)
408
429
 
409
430
    typedef struct {
410
431
      EXCEPTION_REGISTRATION ex_reg;
439
460
            return ExceptionContinueSearch;
440
461
        }
441
462
    }
442
 
# endif /* __GNUC__ */
443
 
 
444
 
 
445
 
  GC_bool GC_mark_some(cold_gc_frame)
446
 
  ptr_t cold_gc_frame;
 
463
# endif /* __GNUC__  && MSWIN32 */
 
464
 
 
465
#ifdef GC_WIN32_THREADS
 
466
  extern GC_bool GC_started_thread_while_stopped(void);
 
467
  /* In win32_threads.c.  Did we invalidate mark phase with an  */
 
468
  /* unexpected thread start?                                   */
 
469
#endif
 
470
 
 
471
# ifdef WRAP_MARK_SOME
 
472
  GC_bool GC_mark_some(ptr_t cold_gc_frame)
447
473
  {
448
474
      GC_bool ret_val;
449
475
 
450
 
#   ifndef __GNUC__
 
476
#   ifdef MSWIN32
 
477
#    ifndef __GNUC__
451
478
      /* Windows 98 appears to asynchronously create and remove  */
452
479
      /* writable memory mappings, for reasons we haven't yet    */
453
480
      /* understood.  Since we look for writable regions to      */
457
484
      /* This code does not appear to be necessary for Windows   */
458
485
      /* 95/NT/2000. Note that this code should never generate   */
459
486
      /* an incremental GC write fault.                          */
 
487
      /* It's conceivable that this is the same issue with       */
 
488
      /* terminating threads that we see with Linux and          */
 
489
      /* USE_PROC_FOR_LIBRARIES.                                 */
460
490
 
461
491
      __try {
 
492
          ret_val = GC_mark_some_inner(cold_gc_frame);
 
493
      } __except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
 
494
                EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
 
495
          goto handle_ex;
 
496
      }
 
497
#     ifdef GC_WIN32_THREADS
 
498
        /* With DllMain-based thread tracking, a thread may have        */
 
499
        /* started while we were marking.  This is logically equivalent */
 
500
        /* to the exception case; our results are invalid and we have   */
 
501
        /* to start over.  This cannot be prevented since we can't      */
 
502
        /* block in DllMain.                                            */
 
503
        if (GC_started_thread_while_stopped()) goto handle_ex;
 
504
#     endif
 
505
     rm_handler:
 
506
      return ret_val;
462
507
 
463
 
#   else /* __GNUC__ */
 
508
#    else /* __GNUC__ */
464
509
 
465
510
      /* Manually install an exception handler since GCC does    */
466
511
      /* not yet support Structured Exception Handling (SEH) on  */
472
517
      er.ex_reg.handler = mark_ex_handler;
473
518
      asm volatile ("movl %%fs:0, %0" : "=r" (er.ex_reg.prev));
474
519
      asm volatile ("movl %0, %%fs:0" : : "r" (&er));
475
 
 
476
 
#   endif /* __GNUC__ */
477
 
 
478
 
          ret_val = GC_mark_some_inner(cold_gc_frame);
479
 
 
480
 
#   ifndef __GNUC__
481
 
 
482
 
      } __except (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION ?
483
 
                EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) {
484
 
 
485
 
#   else /* __GNUC__ */
486
 
 
487
 
          /* Prevent GCC from considering the following code unreachable */
488
 
          /* and thus eliminating it.                                    */
489
 
          if (er.alt_path != 0)
490
 
              goto rm_handler;
491
 
 
492
 
handle_ex:
493
 
          /* Execution resumes from here on an access violation. */
494
 
 
495
 
#   endif /* __GNUC__ */
496
 
 
497
 
#         ifdef CONDPRINT
498
 
            if (GC_print_stats) {
499
 
              GC_printf0("Caught ACCESS_VIOLATION in marker. "
500
 
                         "Memory mapping disappeared.\n");
501
 
            }
502
 
#         endif /* CONDPRINT */
503
 
 
504
 
          /* We have bad roots on the stack.  Discard mark stack.  */
505
 
          /* Rescan from marked objects.  Redetermine roots.     */
506
 
          GC_invalidate_mark_state();   
507
 
          scan_ptr = 0;
508
 
 
509
 
          ret_val = FALSE;
510
 
 
511
 
#   ifndef __GNUC__
512
 
 
513
 
      }
514
 
 
515
 
#   else /* __GNUC__ */
516
 
 
517
 
rm_handler:
 
520
      ret_val = GC_mark_some_inner(cold_gc_frame);
 
521
      /* Prevent GCC from considering the following code unreachable */
 
522
      /* and thus eliminating it.                                    */
 
523
        if (er.alt_path == 0)
 
524
          goto handle_ex;
 
525
    rm_handler:
518
526
      /* Uninstall the exception handler */
519
527
      asm volatile ("mov %0, %%fs:0" : : "r" (er.ex_reg.prev));
520
 
 
521
 
#   endif /* __GNUC__ */
522
 
 
523
 
      return ret_val;
 
528
      return ret_val;
 
529
 
 
530
#    endif /* __GNUC__ */
 
531
#   else /* !MSWIN32 */
 
532
      /* Here we are handling the case in which /proc is used for root  */
 
533
      /* finding, and we have threads.  We may find a stack for a       */
 
534
      /* thread that is in the process of exiting, and disappears       */
 
535
      /* while we are marking it.  This seems extremely difficult to    */
 
536
      /* avoid otherwise.                                               */
 
537
      if (GC_incremental)
 
538
              WARN("Incremental GC incompatible with /proc roots\n", 0);
 
539
        /* I'm not sure if this could still work ...    */
 
540
      GC_setup_temporary_fault_handler();
 
541
      if(SETJMP(GC_jmp_buf) != 0) goto handle_ex;
 
542
      ret_val = GC_mark_some_inner(cold_gc_frame);
 
543
    rm_handler:
 
544
      GC_reset_fault_handler();
 
545
      return ret_val;
 
546
      
 
547
#   endif /* !MSWIN32 */
 
548
 
 
549
handle_ex:
 
550
    /* Exception handler starts here for all cases. */
 
551
      if (GC_print_stats) {
 
552
        GC_log_printf("Caught ACCESS_VIOLATION in marker. "
 
553
                      "Memory mapping disappeared.\n");
 
554
      }
 
555
 
 
556
      /* We have bad roots on the stack.  Discard mark stack.   */
 
557
      /* Rescan from marked objects.  Redetermine roots.        */
 
558
      GC_invalidate_mark_state();       
 
559
      scan_ptr = 0;
 
560
 
 
561
      ret_val = FALSE;
 
562
      goto rm_handler;  // Back to platform-specific code.
524
563
  }
525
 
#endif /* MSWIN32 */
526
 
 
527
 
 
528
 
GC_bool GC_mark_stack_empty()
 
564
#endif /* WRAP_MARK_SOME */
 
565
 
 
566
 
 
567
GC_bool GC_mark_stack_empty(void)
529
568
{
530
569
    return(GC_mark_stack_top < GC_mark_stack);
531
570
}       
532
571
 
533
 
#ifdef PROF_MARKER
534
 
    word GC_prof_array[10];
535
 
#   define PROF(n) GC_prof_array[n]++
536
 
#else
537
 
#   define PROF(n)
538
 
#endif
539
 
 
540
 
/* Given a pointer to someplace other than a small object page or the   */
541
 
/* first page of a large object, either:                                */
542
 
/*      - return a pointer to somewhere in the first page of the large  */
543
 
/*        object, if current points to a large object.                  */
544
 
/*        In this case *hhdr is replaced with a pointer to the header   */
545
 
/*        for the large object.                                         */
546
 
/*      - just return current if it does not point to a large object.   */
547
 
/*ARGSUSED*/
548
 
ptr_t GC_find_start(current, hhdr, new_hdr_p)
549
 
register ptr_t current;
550
 
register hdr *hhdr, **new_hdr_p;
551
 
{
552
 
    if (GC_all_interior_pointers) {
553
 
        if (hhdr != 0) {
554
 
            register ptr_t orig = current;
555
 
            
556
 
            current = (ptr_t)HBLKPTR(current);
557
 
            do {
558
 
              current = current - HBLKSIZE*(word)hhdr;
559
 
              hhdr = HDR(current);
560
 
            } while(IS_FORWARDING_ADDR_OR_NIL(hhdr));
561
 
            /* current points to near the start of the large object */
562
 
            if (hhdr -> hb_flags & IGNORE_OFF_PAGE) return(orig);
563
 
            if ((word *)orig - (word *)current
564
 
                 >= (ptrdiff_t)(hhdr->hb_sz)) {
565
 
                /* Pointer past the end of the block */
566
 
                return(orig);
567
 
            }
568
 
            *new_hdr_p = hhdr;
569
 
            return(current);
570
 
        } else {
571
 
            return(current);
572
 
        }
573
 
    } else {
574
 
        return(current);
575
 
    }
576
 
}
577
 
 
578
 
void GC_invalidate_mark_state()
 
572
void GC_invalidate_mark_state(void)
579
573
{
580
574
    GC_mark_state = MS_INVALID;
581
575
    GC_mark_stack_top = GC_mark_stack-1;
582
576
}
583
577
 
584
 
mse * GC_signal_mark_stack_overflow(msp)
585
 
mse * msp;
 
578
mse * GC_signal_mark_stack_overflow(mse *msp)
586
579
{
587
580
    GC_mark_state = MS_INVALID;
588
581
    GC_mark_stack_too_small = TRUE;
589
 
#   ifdef CONDPRINT
590
 
      if (GC_print_stats) {
591
 
        GC_printf1("Mark stack overflow; current size = %lu entries\n",
592
 
                    GC_mark_stack_size);
593
 
      }
594
 
#   endif
 
582
    if (GC_print_stats) {
 
583
        GC_log_printf("Mark stack overflow; current size = %lu entries\n",
 
584
                      GC_mark_stack_size);
 
585
    }
595
586
    return(msp - GC_MARK_STACK_DISCARDS);
596
587
}
597
588
 
598
589
/*
599
590
 * Mark objects pointed to by the regions described by
600
 
 * mark stack entries between GC_mark_stack and GC_mark_stack_top,
 
591
 * mark stack entries between mark_stack and mark_stack_top,
601
592
 * inclusive.  Assumes the upper limit of a mark stack entry
602
593
 * is never 0.  A mark stack entry never has size 0.
603
594
 * We try to traverse on the order of a hblk of memory before we return.
609
600
 * encoding, we optionally maintain a cache for the block address to
610
601
 * header mapping, we prefetch when an object is "grayed", etc. 
611
602
 */
612
 
mse * GC_mark_from(mark_stack_top, mark_stack, mark_stack_limit)
613
 
mse * mark_stack_top;
614
 
mse * mark_stack;
615
 
mse * mark_stack_limit;
 
603
mse * GC_mark_from(mse *mark_stack_top, mse *mark_stack, mse *mark_stack_limit)
616
604
{
617
 
  int credit = HBLKSIZE;        /* Remaining credit for marking work    */
618
 
  register word * current_p;    /* Pointer to current candidate ptr.    */
619
 
  register word current;        /* Candidate pointer.                   */
620
 
  register word * limit;        /* (Incl) limit of current candidate    */
 
605
  signed_word credit = HBLKSIZE;  /* Remaining credit for marking work  */
 
606
  ptr_t current_p;      /* Pointer to current candidate ptr.    */
 
607
  word current; /* Candidate pointer.                   */
 
608
  ptr_t limit;  /* (Incl) limit of current candidate    */
621
609
                                /* range                                */
622
 
  register word descr;
623
 
  register ptr_t greatest_ha = GC_greatest_plausible_heap_addr;
624
 
  register ptr_t least_ha = GC_least_plausible_heap_addr;
 
610
  word descr;
 
611
  ptr_t greatest_ha = GC_greatest_plausible_heap_addr;
 
612
  ptr_t least_ha = GC_least_plausible_heap_addr;
625
613
  DECLARE_HDR_CACHE;
626
614
 
627
615
# define SPLIT_RANGE_WORDS 128  /* Must be power of 2.          */
652
640
          /* stack.                                                     */
653
641
          GC_ASSERT(descr < (word)GC_greatest_plausible_heap_addr
654
642
                            - (word)GC_least_plausible_heap_addr);
 
643
#         ifdef ENABLE_TRACE
 
644
            if (GC_trace_addr >= current_p
 
645
                && GC_trace_addr < current_p + descr) {
 
646
                GC_log_printf("GC:%d Large section; start %p len %lu\n",
 
647
                              GC_gc_no, current_p, (unsigned long) descr);
 
648
            }
 
649
#         endif /* ENABLE_TRACE */
655
650
#         ifdef PARALLEL_MARK
656
651
#           define SHARE_BYTES 2048
657
652
            if (descr > SHARE_BYTES && GC_parallel
662
657
                                        /* makes sure we handle         */
663
658
                                        /* misaligned pointers.         */
664
659
              mark_stack_top++;
665
 
              current_p = (word *) ((char *)current_p + new_size);
 
660
#             ifdef ENABLE_TRACE
 
661
                if (GC_trace_addr >= current_p
 
662
                    && GC_trace_addr < current_p + descr) {
 
663
                    GC_log_printf("GC:%d splitting (parallel) %p at %p\n",
 
664
                                  GC_gc_no, current_p, current_p + new_size);
 
665
                }
 
666
#             endif /* ENABLE_TRACE */
 
667
              current_p += new_size;
666
668
              descr -= new_size;
667
669
              goto retry;
668
670
            }
669
671
#         endif /* PARALLEL_MARK */
670
672
          mark_stack_top -> mse_start =
671
 
                limit = current_p + SPLIT_RANGE_WORDS-1;
 
673
                limit = current_p + WORDS_TO_BYTES(SPLIT_RANGE_WORDS-1);
672
674
          mark_stack_top -> mse_descr =
673
675
                        descr - WORDS_TO_BYTES(SPLIT_RANGE_WORDS-1);
 
676
#         ifdef ENABLE_TRACE
 
677
            if (GC_trace_addr >= current_p
 
678
                && GC_trace_addr < current_p + descr) {
 
679
                GC_log_printf("GC:%d splitting %p at %p\n",
 
680
                              GC_gc_no, current_p, limit);
 
681
            }
 
682
#         endif /* ENABLE_TRACE */
674
683
          /* Make sure that pointers overlapping the two ranges are     */
675
684
          /* considered.                                                */
676
 
          limit = (word *)((char *)limit + sizeof(word) - ALIGNMENT);
 
685
          limit += sizeof(word) - ALIGNMENT;
677
686
          break;
678
687
        case GC_DS_BITMAP:
679
688
          mark_stack_top--;
 
689
#         ifdef ENABLE_TRACE
 
690
            if (GC_trace_addr >= current_p
 
691
                && GC_trace_addr < current_p + WORDS_TO_BYTES(WORDSZ-2)) {
 
692
                GC_log_printf("GC:%d Tracing from %p bitmap descr %lu\n",
 
693
                              GC_gc_no, current_p, (unsigned long) descr);
 
694
            }
 
695
#         endif /* ENABLE_TRACE */
680
696
          descr &= ~GC_DS_TAGS;
681
697
          credit -= WORDS_TO_BYTES(WORDSZ/2); /* guess */
682
698
          while (descr != 0) {
683
699
            if ((signed_word)descr < 0) {
684
 
              current = *current_p;
 
700
              current = *(word *)current_p;
685
701
              FIXUP_POINTER(current);
686
702
              if ((ptr_t)current >= least_ha && (ptr_t)current < greatest_ha) {
687
703
                PREFETCH((ptr_t)current);
688
 
                HC_PUSH_CONTENTS((ptr_t)current, mark_stack_top,
 
704
#               ifdef ENABLE_TRACE
 
705
                  if (GC_trace_addr == current_p) {
 
706
                    GC_log_printf("GC:%d Considering(3) %p -> %p\n",
 
707
                                  GC_gc_no, current_p, (ptr_t) current);
 
708
                  }
 
709
#               endif /* ENABLE_TRACE */
 
710
                PUSH_CONTENTS((ptr_t)current, mark_stack_top,
689
711
                              mark_stack_limit, current_p, exit1);
690
712
              }
691
713
            }
692
714
            descr <<= 1;
693
 
            ++ current_p;
 
715
            current_p += sizeof(word);
694
716
          }
695
717
          continue;
696
718
        case GC_DS_PROC:
697
719
          mark_stack_top--;
 
720
#         ifdef ENABLE_TRACE
 
721
            if (GC_trace_addr >= current_p
 
722
                && GC_base(current_p) != 0
 
723
                && GC_base(current_p) == GC_base(GC_trace_addr)) {
 
724
                GC_log_printf("GC:%d Tracing from %p proc descr %lu\n",
 
725
                              GC_gc_no, current_p, (unsigned long) descr);
 
726
            }
 
727
#         endif /* ENABLE_TRACE */
698
728
          credit -= GC_PROC_BYTES;
699
729
          mark_stack_top =
700
730
              (*PROC(descr))
701
 
                    (current_p, mark_stack_top,
 
731
                    ((word *)current_p, mark_stack_top,
702
732
                    mark_stack_limit, ENV(descr));
703
733
          continue;
704
734
        case GC_DS_PER_OBJECT:
705
735
          if ((signed_word)descr >= 0) {
706
736
            /* Descriptor is in the object.     */
707
 
            descr = *(word *)((ptr_t)current_p + descr - GC_DS_PER_OBJECT);
 
737
            descr = *(word *)(current_p + descr - GC_DS_PER_OBJECT);
708
738
          } else {
709
739
            /* Descriptor is in type descriptor pointed to by first     */
710
740
            /* word in object.                                          */
722
752
                continue;
723
753
            }
724
754
            descr = *(word *)(type_descr
725
 
                              - (descr - (GC_DS_PER_OBJECT
726
 
                                          - GC_INDIR_PER_OBJ_BIAS)));
 
755
                              - (descr + (GC_INDIR_PER_OBJ_BIAS
 
756
                                          - GC_DS_PER_OBJECT)));
727
757
          }
728
758
          if (0 == descr) {
729
759
              /* Can happen either because we generated a 0 descriptor  */
730
 
              /* or we saw a pointer to a free object.                  */
 
760
              /* or we saw a pointer to a free object.          */
731
761
              mark_stack_top--;
732
762
              continue;
733
763
          }
735
765
      }
736
766
    } else /* Small object with length descriptor */ {
737
767
      mark_stack_top--;
738
 
      limit = (word *)(((ptr_t)current_p) + (word)descr);
 
768
      limit = current_p + (word)descr;
739
769
    }
 
770
#   ifdef ENABLE_TRACE
 
771
        if (GC_trace_addr >= current_p
 
772
            && GC_trace_addr < limit) {
 
773
            GC_log_printf("GC:%d Tracing from %p len %lu\n",
 
774
                          GC_gc_no, current_p, (unsigned long) descr);
 
775
        }
 
776
#   endif /* ENABLE_TRACE */
740
777
    /* The simple case in which we're scanning a range. */
741
778
    GC_ASSERT(!((word)current_p & (ALIGNMENT-1)));
742
 
    credit -= (ptr_t)limit - (ptr_t)current_p;
743
 
    limit -= 1;
 
779
    credit -= limit - current_p;
 
780
    limit -= sizeof(word);
744
781
    {
745
782
#     define PREF_DIST 4
746
783
 
754
791
        /* generating slightly better code.  Overall gcc code quality   */
755
792
        /* for this loop is still not great.                            */
756
793
        for(;;) {
757
 
          PREFETCH((ptr_t)limit - PREF_DIST*CACHE_LINE_SIZE);
 
794
          PREFETCH(limit - PREF_DIST*CACHE_LINE_SIZE);
758
795
          GC_ASSERT(limit >= current_p);
759
 
          deferred = *limit;
 
796
          deferred = *(word *)limit;
760
797
          FIXUP_POINTER(deferred);
761
 
          limit = (word *)((char *)limit - ALIGNMENT);
 
798
          limit -= ALIGNMENT;
762
799
          if ((ptr_t)deferred >= least_ha && (ptr_t)deferred <  greatest_ha) {
763
800
            PREFETCH((ptr_t)deferred);
764
801
            break;
766
803
          if (current_p > limit) goto next_object;
767
804
          /* Unroll once, so we don't do too many of the prefetches     */
768
805
          /* based on limit.                                            */
769
 
          deferred = *limit;
 
806
          deferred = *(word *)limit;
770
807
          FIXUP_POINTER(deferred);
771
 
          limit = (word *)((char *)limit - ALIGNMENT);
 
808
          limit -= ALIGNMENT;
772
809
          if ((ptr_t)deferred >= least_ha && (ptr_t)deferred <  greatest_ha) {
773
810
            PREFETCH((ptr_t)deferred);
774
811
            break;
779
816
 
780
817
      while (current_p <= limit) {
781
818
        /* Empirically, unrolling this loop doesn't help a lot. */
782
 
        /* Since HC_PUSH_CONTENTS expands to a lot of code,     */
 
819
        /* Since PUSH_CONTENTS expands to a lot of code,        */
783
820
        /* we don't.                                            */
784
 
        current = *current_p;
 
821
        current = *(word *)current_p;
785
822
        FIXUP_POINTER(current);
786
 
        PREFETCH((ptr_t)current_p + PREF_DIST*CACHE_LINE_SIZE);
 
823
        PREFETCH(current_p + PREF_DIST*CACHE_LINE_SIZE);
787
824
        if ((ptr_t)current >= least_ha && (ptr_t)current <  greatest_ha) {
788
825
          /* Prefetch the contents of the object we just pushed.  It's  */
789
826
          /* likely we will need them soon.                             */
790
827
          PREFETCH((ptr_t)current);
791
 
          HC_PUSH_CONTENTS((ptr_t)current, mark_stack_top,
 
828
#         ifdef ENABLE_TRACE
 
829
            if (GC_trace_addr == current_p) {
 
830
                GC_log_printf("GC:%d Considering(1) %p -> %p\n",
 
831
                              GC_gc_no, current_p, (ptr_t) current);
 
832
            }
 
833
#         endif /* ENABLE_TRACE */
 
834
          PUSH_CONTENTS((ptr_t)current, mark_stack_top,
792
835
                           mark_stack_limit, current_p, exit2);
793
836
        }
794
 
        current_p = (word *)((char *)current_p + ALIGNMENT);
 
837
        current_p += ALIGNMENT;
795
838
      }
796
839
 
797
840
#     ifndef SMALL_CONFIG
798
841
        /* We still need to mark the entry we previously prefetched.    */
799
 
        /* We alrady know that it passes the preliminary pointer        */
 
842
        /* We already know that it passes the preliminary pointer       */
800
843
        /* validity test.                                               */
801
 
        HC_PUSH_CONTENTS((ptr_t)deferred, mark_stack_top,
 
844
#       ifdef ENABLE_TRACE
 
845
            if (GC_trace_addr == current_p) {
 
846
                GC_log_printf("GC:%d Considering(2) %p -> %p\n",
 
847
                              GC_gc_no, current_p, (ptr_t) deferred);
 
848
            }
 
849
#       endif /* ENABLE_TRACE */
 
850
        PUSH_CONTENTS((ptr_t)deferred, mark_stack_top,
802
851
                         mark_stack_limit, current_p, exit4);
803
852
        next_object:;
804
853
#     endif
813
862
GC_bool GC_help_wanted = FALSE;
814
863
unsigned GC_helper_count = 0;
815
864
unsigned GC_active_count = 0;
816
 
mse * VOLATILE GC_first_nonempty;
817
865
word GC_mark_no = 0;
818
866
 
819
867
#define LOCAL_MARK_STACK_SIZE HBLKSIZE
834
882
    mse *top = local - 1;
835
883
    unsigned i = 0;
836
884
 
837
 
    /* Make sure that prior writes to the mark stack are visible. */
838
 
    /* On some architectures, the fact that the reads are         */
839
 
    /* volatile should suffice.                                   */
840
 
#   if !defined(IA64) && !defined(HP_PA) && !defined(I386)
841
 
      GC_memory_barrier();
842
 
#   endif
843
885
    GC_ASSERT(high >= low-1 && high - low + 1 <= GC_mark_stack_size);
844
886
    for (p = low; p <= high && i <= max; ++p) {
845
 
        word descr = *(volatile word *) &(p -> mse_descr);
846
 
        /* In the IA64 memory model, the following volatile store is    */
847
 
        /* ordered after this read of descr.  Thus a thread must read   */
848
 
        /* the original nonzero value.  HP_PA appears to be similar,    */
849
 
        /* and if I'm reading the P4 spec correctly, X86 is probably    */
850
 
        /* also OK.  In some other cases we need a barrier.             */
851
 
#       if !defined(IA64) && !defined(HP_PA) && !defined(I386)
852
 
          GC_memory_barrier();
853
 
#       endif
 
887
        word descr = AO_load((volatile AO_t *) &(p -> mse_descr));
854
888
        if (descr != 0) {
855
 
            *(volatile word *) &(p -> mse_descr) = 0;
 
889
            /* Must be ordered after read of descr: */
 
890
            AO_store_release_write((volatile AO_t *) &(p -> mse_descr), 0);
856
891
            /* More than one thread may get this entry, but that's only */
857
892
            /* a minor performance problem.                             */
858
893
            ++top;
859
894
            top -> mse_descr = descr;
860
895
            top -> mse_start = p -> mse_start;
861
 
            GC_ASSERT(  (top -> mse_descr & GC_DS_TAGS) != GC_DS_LENGTH || 
862
 
                        top -> mse_descr < (ptr_t)GC_greatest_plausible_heap_addr
863
 
                                           - (ptr_t)GC_least_plausible_heap_addr);
 
896
            GC_ASSERT((top -> mse_descr & GC_DS_TAGS) != GC_DS_LENGTH || 
 
897
                      top -> mse_descr < (ptr_t)GC_greatest_plausible_heap_addr
 
898
                                         - (ptr_t)GC_least_plausible_heap_addr);
864
899
            /* If this is a big object, count it as                     */
865
900
            /* size/256 + 1 objects.                                    */
866
901
            ++i;
882
917
    if (high < low) return;
883
918
    stack_size = high - low + 1;
884
919
    GC_acquire_mark_lock();
885
 
    my_top = GC_mark_stack_top;
 
920
    my_top = GC_mark_stack_top; /* Concurrent modification impossible. */
886
921
    my_start = my_top + 1;
887
922
    if (my_start - GC_mark_stack + stack_size > GC_mark_stack_size) {
888
 
#     ifdef CONDPRINT
889
 
        if (GC_print_stats) {
890
 
          GC_printf0("No room to copy back mark stack.");
891
 
        }
892
 
#     endif
 
923
      if (GC_print_stats) {
 
924
          GC_log_printf("No room to copy back mark stack.");
 
925
      }
893
926
      GC_mark_state = MS_INVALID;
894
927
      GC_mark_stack_too_small = TRUE;
895
928
      /* We drop the local mark stack.  We'll fix things later. */
896
929
    } else {
897
930
      BCOPY(low, my_start, stack_size * sizeof(mse));
898
 
      GC_ASSERT(GC_mark_stack_top = my_top);
899
 
#     if !defined(IA64) && !defined(HP_PA)
900
 
        GC_memory_barrier();
901
 
#     endif
902
 
        /* On IA64, the volatile write acts as a release barrier. */
903
 
      GC_mark_stack_top = my_top + stack_size;
 
931
      GC_ASSERT((mse *)AO_load((volatile AO_t *)(&GC_mark_stack_top))
 
932
                == my_top);
 
933
      AO_store_release_write((volatile AO_t *)(&GC_mark_stack_top),
 
934
                             (AO_t)(my_top + stack_size));
 
935
                /* Ensures visibility of previously written stack contents. */
904
936
    }
905
937
    GC_release_mark_lock();
906
938
    GC_notify_all_marker();
930
962
                return;
931
963
            }
932
964
        }
933
 
        if (GC_mark_stack_top < GC_first_nonempty &&
934
 
            GC_active_count < GC_helper_count
 
965
        if ((mse *)AO_load((volatile AO_t *)(&GC_mark_stack_top))
 
966
            < (mse *)AO_load(&GC_first_nonempty)
 
967
            && GC_active_count < GC_helper_count
935
968
            && local_top > local_mark_stack + 1) {
936
969
            /* Try to share the load, since the main stack is empty,    */
937
970
            /* and helper threads are waiting for a refill.             */
938
971
            /* The entries near the bottom of the stack are likely      */
939
972
            /* to require more work.  Thus we return those, eventhough  */
940
973
            /* it's harder.                                             */
941
 
            mse * p;
942
974
            mse * new_bottom = local_mark_stack
943
975
                                + (local_top - local_mark_stack)/2;
944
976
            GC_ASSERT(new_bottom > local_mark_stack
968
1000
 
969
1001
    GC_acquire_mark_lock();
970
1002
    GC_active_count++;
971
 
    my_first_nonempty = GC_first_nonempty;
972
 
    GC_ASSERT(GC_first_nonempty >= GC_mark_stack && 
973
 
              GC_first_nonempty <= GC_mark_stack_top + 1);
974
 
#   ifdef PRINTSTATS
975
 
        GC_printf1("Starting mark helper %lu\n", (unsigned long)id);
976
 
#   endif
 
1003
    my_first_nonempty = (mse *)AO_load(&GC_first_nonempty);
 
1004
    GC_ASSERT((mse *)AO_load(&GC_first_nonempty) >= GC_mark_stack && 
 
1005
              (mse *)AO_load(&GC_first_nonempty) <=
 
1006
              (mse *)AO_load((volatile AO_t *)(&GC_mark_stack_top)) + 1);
 
1007
    if (GC_print_stats == VERBOSE)
 
1008
        GC_log_printf("Starting mark helper %lu\n", (unsigned long)id);
977
1009
    GC_release_mark_lock();
978
1010
    for (;;) {
979
1011
        size_t n_on_stack;
980
1012
        size_t n_to_get;
981
 
        mse *next;
982
1013
        mse * my_top;
983
1014
        mse * local_top;
984
 
        mse * global_first_nonempty = GC_first_nonempty;
 
1015
        mse * global_first_nonempty = (mse *)AO_load(&GC_first_nonempty);
985
1016
 
986
1017
        GC_ASSERT(my_first_nonempty >= GC_mark_stack && 
987
 
                  my_first_nonempty <= GC_mark_stack_top + 1);
 
1018
                  my_first_nonempty <=
 
1019
                  (mse *)AO_load((volatile AO_t *)(&GC_mark_stack_top))  + 1);
988
1020
        GC_ASSERT(global_first_nonempty >= GC_mark_stack && 
989
 
                  global_first_nonempty <= GC_mark_stack_top + 1);
 
1021
                  global_first_nonempty <= 
 
1022
                  (mse *)AO_load((volatile AO_t *)(&GC_mark_stack_top))  + 1);
990
1023
        if (my_first_nonempty < global_first_nonempty) {
991
1024
            my_first_nonempty = global_first_nonempty;
992
1025
        } else if (global_first_nonempty < my_first_nonempty) {
993
 
            GC_compare_and_exchange((word *)(&GC_first_nonempty), 
994
 
                                   (word) global_first_nonempty,
995
 
                                   (word) my_first_nonempty);
 
1026
            AO_compare_and_swap(&GC_first_nonempty, 
 
1027
                                (AO_t) global_first_nonempty,
 
1028
                                (AO_t) my_first_nonempty);
996
1029
            /* If this fails, we just go ahead, without updating        */
997
1030
            /* GC_first_nonempty.                                       */
998
1031
        }
999
1032
        /* Perhaps we should also update GC_first_nonempty, if it */
1000
1033
        /* is less.  But that would require using atomic updates. */
1001
 
        my_top = GC_mark_stack_top;
 
1034
        my_top = (mse *)AO_load_acquire((volatile AO_t *)(&GC_mark_stack_top));
1002
1035
        n_on_stack = my_top - my_first_nonempty + 1;
1003
1036
        if (0 == n_on_stack) {
1004
1037
            GC_acquire_mark_lock();
1005
1038
            my_top = GC_mark_stack_top;
 
1039
                /* Asynchronous modification impossible here,   */
 
1040
                /* since we hold mark lock.                     */
1006
1041
            n_on_stack = my_top - my_first_nonempty + 1;
1007
1042
            if (0 == n_on_stack) {
1008
1043
                GC_active_count--;
1011
1046
                /* on the stack.                                */
1012
1047
                if (0 == GC_active_count) GC_notify_all_marker();
1013
1048
                while (GC_active_count > 0
1014
 
                       && GC_first_nonempty > GC_mark_stack_top) {
 
1049
                       && (mse *)AO_load(&GC_first_nonempty)
 
1050
                          > GC_mark_stack_top) {
1015
1051
                    /* We will be notified if either GC_active_count    */
1016
1052
                    /* reaches zero, or if more objects are pushed on   */
1017
1053
                    /* the global mark stack.                           */
1018
1054
                    GC_wait_marker();
1019
1055
                }
1020
1056
                if (GC_active_count == 0 &&
1021
 
                    GC_first_nonempty > GC_mark_stack_top) { 
 
1057
                    (mse *)AO_load(&GC_first_nonempty) > GC_mark_stack_top) { 
1022
1058
                    GC_bool need_to_notify = FALSE;
1023
1059
                    /* The above conditions can't be falsified while we */
1024
1060
                    /* hold the mark lock, since neither                */
1028
1064
                    /* both conditions actually held simultaneously.    */
1029
1065
                    GC_helper_count--;
1030
1066
                    if (0 == GC_helper_count) need_to_notify = TRUE;
1031
 
#                   ifdef PRINTSTATS
1032
 
                      GC_printf1(
 
1067
                    if (GC_print_stats == VERBOSE)
 
1068
                      GC_log_printf(
1033
1069
                        "Finished mark helper %lu\n", (unsigned long)id);
1034
 
#                   endif
1035
1070
                    GC_release_mark_lock();
1036
1071
                    if (need_to_notify) GC_notify_all_marker();
1037
1072
                    return;
1052
1087
                                        local_mark_stack, n_to_get,
1053
1088
                                        &my_first_nonempty);
1054
1089
        GC_ASSERT(my_first_nonempty >= GC_mark_stack && 
1055
 
                  my_first_nonempty <= GC_mark_stack_top + 1);
 
1090
                  my_first_nonempty <=
 
1091
                    (mse *)AO_load((volatile AO_t *)(&GC_mark_stack_top)) + 1);
1056
1092
        GC_do_local_mark(local_mark_stack, local_top);
1057
1093
    }
1058
1094
}
1064
1100
void GC_do_parallel_mark()
1065
1101
{
1066
1102
    mse local_mark_stack[LOCAL_MARK_STACK_SIZE];
1067
 
    mse * local_top;
1068
 
    mse * my_top;
1069
1103
 
1070
1104
    GC_acquire_mark_lock();
1071
1105
    GC_ASSERT(I_HOLD_LOCK());
1073
1107
    /* all the time, especially since it's cheap.                       */
1074
1108
    if (GC_help_wanted || GC_active_count != 0 || GC_helper_count != 0)
1075
1109
        ABORT("Tried to start parallel mark in bad state");
1076
 
#   ifdef PRINTSTATS
1077
 
        GC_printf1("Starting marking for mark phase number %lu\n",
 
1110
    if (GC_print_stats == VERBOSE)
 
1111
        GC_log_printf("Starting marking for mark phase number %lu\n",
1078
1112
                   (unsigned long)GC_mark_no);
1079
 
#   endif
1080
 
    GC_first_nonempty = GC_mark_stack;
 
1113
    GC_first_nonempty = (AO_t)GC_mark_stack;
1081
1114
    GC_active_count = 0;
1082
1115
    GC_helper_count = 1;
1083
1116
    GC_help_wanted = TRUE;
1090
1123
    /* Done; clean up.  */
1091
1124
    while (GC_helper_count > 0) GC_wait_marker();
1092
1125
    /* GC_helper_count cannot be incremented while GC_help_wanted == FALSE */
1093
 
#   ifdef PRINTSTATS
1094
 
        GC_printf1(
 
1126
    if (GC_print_stats == VERBOSE)
 
1127
        GC_log_printf(
1095
1128
            "Finished marking for mark phase number %lu\n",
1096
1129
            (unsigned long)GC_mark_no);
1097
 
#   endif
1098
1130
    GC_mark_no++;
1099
1131
    GC_release_mark_lock();
1100
1132
    GC_notify_all_marker();
1107
1139
{
1108
1140
    mse local_mark_stack[LOCAL_MARK_STACK_SIZE];
1109
1141
    unsigned my_id;
1110
 
    mse * my_first_nonempty;
1111
1142
 
1112
1143
    if (!GC_parallel) return;
1113
1144
    GC_acquire_mark_lock();
1114
1145
    while (GC_mark_no < my_mark_no
1115
 
           || !GC_help_wanted && GC_mark_no == my_mark_no) {
 
1146
           || (!GC_help_wanted && GC_mark_no == my_mark_no)) {
1116
1147
      GC_wait_marker();
1117
1148
    }
1118
1149
    my_id = GC_helper_count;
1130
1161
 
1131
1162
#endif /* PARALLEL_MARK */
1132
1163
 
1133
 
/* Allocate or reallocate space for mark stack of size s words  */
1134
 
/* May silently fail.                                           */
1135
 
static void alloc_mark_stack(n)
1136
 
word n;
 
1164
/* Allocate or reallocate space for mark stack of size n entries.  */
 
1165
/* May silently fail.                                              */
 
1166
static void alloc_mark_stack(size_t n)
1137
1167
{
1138
1168
    mse * new_stack = (mse *)GC_scratch_alloc(n * sizeof(struct GC_ms_entry));
 
1169
#   ifdef GWW_VDB
 
1170
      /* Don't recycle a stack segment obtained with the wrong flags.   */
 
1171
      /* Win32 GetWriteWatch requires the right kind of memory.         */
 
1172
      static GC_bool GC_incremental_at_stack_alloc = 0;
 
1173
      GC_bool recycle_old = (!GC_incremental || GC_incremental_at_stack_alloc);
 
1174
 
 
1175
      GC_incremental_at_stack_alloc = GC_incremental;
 
1176
#   else
 
1177
#     define recycle_old 1
 
1178
#   endif
1139
1179
    
1140
1180
    GC_mark_stack_too_small = FALSE;
1141
1181
    if (GC_mark_stack_size != 0) {
1142
1182
        if (new_stack != 0) {
1143
 
          word displ = (word)GC_mark_stack & (GC_page_size - 1);
1144
 
          signed_word size = GC_mark_stack_size * sizeof(struct GC_ms_entry);
 
1183
          if (recycle_old) {
 
1184
            /* Recycle old space */
 
1185
              size_t page_offset = (word)GC_mark_stack & (GC_page_size - 1);
 
1186
              size_t size = GC_mark_stack_size * sizeof(struct GC_ms_entry);
 
1187
              size_t displ = 0;
1145
1188
          
1146
 
          /* Recycle old space */
1147
 
              if (0 != displ) displ = GC_page_size - displ;
 
1189
              if (0 != page_offset) displ = GC_page_size - page_offset;
1148
1190
              size = (size - displ) & ~(GC_page_size - 1);
1149
1191
              if (size > 0) {
1150
1192
                GC_add_to_heap((struct hblk *)
1151
1193
                                ((word)GC_mark_stack + displ), (word)size);
1152
1194
              }
 
1195
          }
1153
1196
          GC_mark_stack = new_stack;
1154
1197
          GC_mark_stack_size = n;
1155
1198
          GC_mark_stack_limit = new_stack + n;
1156
 
#         ifdef CONDPRINT
1157
 
            if (GC_print_stats) {
1158
 
              GC_printf1("Grew mark stack to %lu frames\n",
1159
 
                         (unsigned long) GC_mark_stack_size);
1160
 
            }
1161
 
#         endif
 
1199
          if (GC_print_stats) {
 
1200
              GC_log_printf("Grew mark stack to %lu frames\n",
 
1201
                            (unsigned long) GC_mark_stack_size);
 
1202
          }
1162
1203
        } else {
1163
 
#         ifdef CONDPRINT
1164
 
            if (GC_print_stats) {
1165
 
              GC_printf1("Failed to grow mark stack to %lu frames\n",
1166
 
                         (unsigned long) n);
1167
 
            }
1168
 
#         endif
 
1204
          if (GC_print_stats) {
 
1205
              GC_log_printf("Failed to grow mark stack to %lu frames\n",
 
1206
                            (unsigned long) n);
 
1207
          }
1169
1208
        }
1170
1209
    } else {
1171
1210
        if (new_stack == 0) {
1172
 
            GC_err_printf0("No space for mark stack\n");
 
1211
            GC_err_printf("No space for mark stack\n");
1173
1212
            EXIT();
1174
1213
        }
1175
1214
        GC_mark_stack = new_stack;
1191
1230
 * Should only be used if there is no possibility of mark stack
1192
1231
 * overflow.
1193
1232
 */
1194
 
void GC_push_all(bottom, top)
1195
 
ptr_t bottom;
1196
 
ptr_t top;
 
1233
void GC_push_all(ptr_t bottom, ptr_t top)
1197
1234
{
1198
1235
    register word length;
1199
1236
    
1209
1246
        length += GC_DS_TAGS;
1210
1247
        length &= ~GC_DS_TAGS;
1211
1248
#   endif
1212
 
    GC_mark_stack_top -> mse_start = (word *)bottom;
 
1249
    GC_mark_stack_top -> mse_start = bottom;
1213
1250
    GC_mark_stack_top -> mse_descr = length;
1214
1251
}
1215
1252
 
1223
1260
 * or if it marks each object before pushing it, thus ensuring progress
1224
1261
 * in the event of a stack overflow.)
1225
1262
 */
1226
 
void GC_push_selected(bottom, top, dirty_fn, push_fn)
1227
 
ptr_t bottom;
1228
 
ptr_t top;
1229
 
int (*dirty_fn) GC_PROTO((struct hblk * h));
1230
 
void (*push_fn) GC_PROTO((ptr_t bottom, ptr_t top));
 
1263
void GC_push_selected(ptr_t bottom, ptr_t top,
 
1264
                      int (*dirty_fn) (struct hblk *),
 
1265
                      void (*push_fn) (ptr_t, ptr_t))
1231
1266
{
1232
 
    register struct hblk * h;
 
1267
    struct hblk * h;
1233
1268
 
1234
 
    bottom = (ptr_t)(((long) bottom + ALIGNMENT-1) & ~(ALIGNMENT-1));
1235
 
    top = (ptr_t)(((long) top) & ~(ALIGNMENT-1));
 
1269
    bottom = (ptr_t)(((word) bottom + ALIGNMENT-1) & ~(ALIGNMENT-1));
 
1270
    top = (ptr_t)(((word) top) & ~(ALIGNMENT-1));
1236
1271
 
1237
1272
    if (top == 0 || bottom == top) return;
1238
1273
    h = HBLKPTR(bottom + HBLKSIZE);
1280
1315
#endif
1281
1316
 
1282
1317
 
1283
 
void GC_push_conditional(bottom, top, all)
1284
 
ptr_t bottom;
1285
 
ptr_t top;
1286
 
int all;
 
1318
void GC_push_conditional(ptr_t bottom, ptr_t top, GC_bool all)
1287
1319
{
1288
1320
    if (all) {
1289
1321
      if (GC_dirty_maintained) {
1303
1335
#endif
1304
1336
 
1305
1337
# if defined(MSWIN32) || defined(MSWINCE)
1306
 
  void __cdecl GC_push_one(p)
1307
 
# else
1308
 
  void GC_push_one(p)
1309
 
# endif
1310
 
word p;
1311
 
{
1312
 
    GC_PUSH_ONE_STACK(p, MARKED_FROM_REGISTER);
1313
 
}
1314
 
 
1315
 
struct GC_ms_entry *GC_mark_and_push(obj, mark_stack_ptr, mark_stack_limit, src)
1316
 
GC_PTR obj;
1317
 
struct GC_ms_entry * mark_stack_ptr;
1318
 
struct GC_ms_entry * mark_stack_limit;
1319
 
GC_PTR *src;
1320
 
{
1321
 
   PREFETCH(obj);
1322
 
   PUSH_CONTENTS(obj, mark_stack_ptr /* modified */, mark_stack_limit, src,
1323
 
                 was_marked /* internally generated exit label */);
1324
 
   return mark_stack_ptr;
1325
 
}
1326
 
 
1327
 
# ifdef __STDC__
1328
 
#   define BASE(p) (word)GC_base((void *)(p))
1329
 
# else
1330
 
#   define BASE(p) (word)GC_base((char *)(p))
1331
 
# endif
 
1338
  void __cdecl GC_push_one(word p)
 
1339
# else
 
1340
  void GC_push_one(word p)
 
1341
# endif
 
1342
{
 
1343
    GC_PUSH_ONE_STACK((ptr_t)p, MARKED_FROM_REGISTER);
 
1344
}
 
1345
 
 
1346
struct GC_ms_entry *GC_mark_and_push(void *obj,
 
1347
                                     mse *mark_stack_ptr,
 
1348
                                     mse *mark_stack_limit,
 
1349
                                     void **src)
 
1350
{
 
1351
    hdr * hhdr;
 
1352
 
 
1353
    PREFETCH(obj);
 
1354
    GET_HDR(obj, hhdr);
 
1355
    if (EXPECT(IS_FORWARDING_ADDR_OR_NIL(hhdr),FALSE)) {
 
1356
      if (GC_all_interior_pointers) {
 
1357
        hhdr = GC_find_header(GC_base(obj));
 
1358
        if (hhdr == 0) {
 
1359
          GC_ADD_TO_BLACK_LIST_NORMAL(obj, src);
 
1360
          return mark_stack_ptr;
 
1361
        }
 
1362
      } else {
 
1363
        GC_ADD_TO_BLACK_LIST_NORMAL(obj, src);
 
1364
        return mark_stack_ptr;
 
1365
      }
 
1366
    }
 
1367
    if (EXPECT(HBLK_IS_FREE(hhdr),0)) {
 
1368
        GC_ADD_TO_BLACK_LIST_NORMAL(obj, src);
 
1369
        return mark_stack_ptr;
 
1370
    }
 
1371
 
 
1372
    PUSH_CONTENTS_HDR(obj, mark_stack_ptr /* modified */, mark_stack_limit,
 
1373
                      src, was_marked, hhdr, TRUE);
 
1374
 was_marked:
 
1375
    return mark_stack_ptr;
 
1376
}
1332
1377
 
1333
1378
/* Mark and push (i.e. gray) a single object p onto the main    */
1334
1379
/* mark stack.  Consider p to be valid if it is an interior     */
1338
1383
/* Mark bits are NOT atomically updated.  Thus this must be the */
1339
1384
/* only thread setting them.                                    */
1340
1385
# if defined(PRINT_BLACK_LIST) || defined(KEEP_BACK_PTRS)
1341
 
    void GC_mark_and_push_stack(p, source)
1342
 
    ptr_t source;
 
1386
    void GC_mark_and_push_stack(ptr_t p, ptr_t source)
1343
1387
# else
1344
 
    void GC_mark_and_push_stack(p)
 
1388
    void GC_mark_and_push_stack(ptr_t p)
1345
1389
#   define source 0
1346
1390
# endif
1347
 
register word p;
1348
1391
{
1349
 
    register word r;
1350
 
    register hdr * hhdr; 
1351
 
    register int displ;
 
1392
    hdr * hhdr; 
 
1393
    ptr_t r = p;
1352
1394
  
 
1395
    PREFETCH(p);
1353
1396
    GET_HDR(p, hhdr);
1354
 
    if (IS_FORWARDING_ADDR_OR_NIL(hhdr)) {
 
1397
    if (EXPECT(IS_FORWARDING_ADDR_OR_NIL(hhdr),FALSE)) {
1355
1398
        if (hhdr != 0) {
1356
 
          r = BASE(p);
 
1399
          r = GC_base(p);
1357
1400
          hhdr = HDR(r);
1358
 
          displ = BYTES_TO_WORDS(HBLKDISPL(r));
1359
 
        }
1360
 
    } else {
1361
 
        register map_entry_type map_entry;
1362
 
        
1363
 
        displ = HBLKDISPL(p);
1364
 
        map_entry = MAP_ENTRY((hhdr -> hb_map), displ);
1365
 
        if (map_entry >= MAX_OFFSET) {
1366
 
          if (map_entry == OFFSET_TOO_BIG || !GC_all_interior_pointers) {
1367
 
              r = BASE(p);
1368
 
              displ = BYTES_TO_WORDS(HBLKDISPL(r));
1369
 
              if (r == 0) hhdr = 0;
1370
 
          } else {
1371
 
              /* Offset invalid, but map reflects interior pointers     */
1372
 
              hhdr = 0;
1373
 
          }
1374
 
        } else {
1375
 
          displ = BYTES_TO_WORDS(displ);
1376
 
          displ -= map_entry;
1377
 
          r = (word)((word *)(HBLKPTR(p)) + displ);
1378
 
        }
1379
 
    }
1380
 
    /* If hhdr != 0 then r == GC_base(p), only we did it faster. */
1381
 
    /* displ is the word index within the block.                 */
1382
 
    if (hhdr == 0) {
1383
 
#       ifdef PRINT_BLACK_LIST
1384
 
          GC_add_to_black_list_stack(p, source);
1385
 
#       else
1386
 
          GC_add_to_black_list_stack(p);
1387
 
#       endif
1388
 
#       undef source  /* In case we had to define it. */
1389
 
    } else {
1390
 
        if (!mark_bit_from_hdr(hhdr, displ)) {
1391
 
            set_mark_bit_from_hdr(hhdr, displ);
1392
 
            GC_STORE_BACK_PTR(source, (ptr_t)r);
1393
 
            PUSH_OBJ((word *)r, hhdr, GC_mark_stack_top,
1394
 
                     GC_mark_stack_limit);
1395
 
        }
1396
 
    }
 
1401
        }
 
1402
        if (hhdr == 0) {
 
1403
            GC_ADD_TO_BLACK_LIST_STACK(p, source);
 
1404
            return;
 
1405
        }
 
1406
    }
 
1407
    if (EXPECT(HBLK_IS_FREE(hhdr),0)) {
 
1408
        GC_ADD_TO_BLACK_LIST_NORMAL(p, src);
 
1409
        return;
 
1410
    }
 
1411
#   if defined(MANUAL_VDB) && defined(THREADS)
 
1412
      /* Pointer is on the stack.  We may have dirtied the object       */
 
1413
      /* it points to, but not yet have called GC_dirty();      */
 
1414
      GC_dirty(p);      /* Implicitly affects entire object.    */
 
1415
#   endif
 
1416
    PUSH_CONTENTS_HDR(r, GC_mark_stack_top, GC_mark_stack_limit,
 
1417
                      source, mark_and_push_exit, hhdr, FALSE);
 
1418
  mark_and_push_exit: ;
 
1419
    /* We silently ignore pointers to near the end of a block,  */
 
1420
    /* which is very mildly suboptimal.                         */
 
1421
    /* FIXME: We should probably add a header word to address   */
 
1422
    /* this.                                                    */
1397
1423
}
1398
1424
 
1399
1425
# ifdef TRACE_BUF
1403
1429
struct trace_entry {
1404
1430
    char * kind;
1405
1431
    word gc_no;
1406
 
    word words_allocd;
 
1432
    word bytes_allocd;
1407
1433
    word arg1;
1408
1434
    word arg2;
1409
1435
} GC_trace_buf[TRACE_ENTRIES];
1414
1440
{
1415
1441
    GC_trace_buf[GC_trace_buf_ptr].kind = kind;
1416
1442
    GC_trace_buf[GC_trace_buf_ptr].gc_no = GC_gc_no;
1417
 
    GC_trace_buf[GC_trace_buf_ptr].words_allocd = GC_words_allocd;
 
1443
    GC_trace_buf[GC_trace_buf_ptr].bytes_allocd = GC_bytes_allocd;
1418
1444
    GC_trace_buf[GC_trace_buf_ptr].arg1 = arg1 ^ 0x80000000;
1419
1445
    GC_trace_buf[GC_trace_buf_ptr].arg2 = arg2 ^ 0x80000000;
1420
1446
    GC_trace_buf_ptr++;
1431
1457
        if (i < 0) i = TRACE_ENTRIES-1;
1432
1458
        p = GC_trace_buf + i;
1433
1459
        if (p -> gc_no < gc_no || p -> kind == 0) return;
1434
 
        printf("Trace:%s (gc:%d,words:%d) 0x%X, 0x%X\n",
1435
 
                p -> kind, p -> gc_no, p -> words_allocd,
 
1460
        printf("Trace:%s (gc:%d,bytes:%d) 0x%X, 0x%X\n",
 
1461
                p -> kind, p -> gc_no, p -> bytes_allocd,
1436
1462
                (p -> arg1) ^ 0x80000000, (p -> arg2) ^ 0x80000000);
1437
1463
    }
1438
1464
    printf("Trace incomplete\n");
1446
1472
 * and scans the entire region immediately, in case the contents
1447
1473
 * change.
1448
1474
 */
1449
 
void GC_push_all_eager(bottom, top)
1450
 
ptr_t bottom;
1451
 
ptr_t top;
 
1475
void GC_push_all_eager(ptr_t bottom, ptr_t top)
1452
1476
{
1453
1477
    word * b = (word *)(((word) bottom + ALIGNMENT-1) & ~(ALIGNMENT-1));
1454
1478
    word * t = (word *)(((word) top) & ~(ALIGNMENT-1));
1455
1479
    register word *p;
1456
 
    register word q;
 
1480
    register ptr_t q;
1457
1481
    register word *lim;
1458
1482
    register ptr_t greatest_ha = GC_greatest_plausible_heap_addr;
1459
1483
    register ptr_t least_ha = GC_least_plausible_heap_addr;
1464
1488
    /* check all pointers in range and push if they appear      */
1465
1489
    /* to be valid.                                             */
1466
1490
      lim = t - 1 /* longword */;
1467
 
      for (p = b; p <= lim; p = (word *)(((char *)p) + ALIGNMENT)) {
1468
 
        q = *p;
1469
 
        GC_PUSH_ONE_STACK(q, p);
 
1491
      for (p = b; p <= lim; p = (word *)(((ptr_t)p) + ALIGNMENT)) {
 
1492
        q = (ptr_t)(*p);
 
1493
        GC_PUSH_ONE_STACK((ptr_t)q, p);
1470
1494
      }
1471
1495
#   undef GC_greatest_plausible_heap_addr
1472
1496
#   undef GC_least_plausible_heap_addr
1479
1503
 * register values are not lost.
1480
1504
 * Cold_gc_frame delimits the stack section that must be scanned
1481
1505
 * eagerly.  A zero value indicates that no eager scanning is needed.
 
1506
 * We don't need to worry about the MANUAL_VDB case here, since this
 
1507
 * is only called in the single-threaded case.  We assume that we
 
1508
 * cannot collect between an assignment and the corresponding
 
1509
 * GC_dirty() call.
1482
1510
 */
1483
 
void GC_push_all_stack_partially_eager(bottom, top, cold_gc_frame)
1484
 
ptr_t bottom;
1485
 
ptr_t top;
1486
 
ptr_t cold_gc_frame;
 
1511
void GC_push_all_stack_partially_eager(ptr_t bottom, ptr_t top,
 
1512
                                       ptr_t cold_gc_frame)
1487
1513
{
1488
1514
  if (!NEED_FIXUP_POINTER && GC_all_interior_pointers) {
1489
1515
    /* Push the hot end of the stack eagerly, so that register values   */
1510
1536
}
1511
1537
#endif /* !THREADS */
1512
1538
 
1513
 
void GC_push_all_stack(bottom, top)
1514
 
ptr_t bottom;
1515
 
ptr_t top;
 
1539
void GC_push_all_stack(ptr_t bottom, ptr_t top)
1516
1540
{
1517
 
  if (!NEED_FIXUP_POINTER && GC_all_interior_pointers) {
1518
 
    GC_push_all(bottom, top);
1519
 
  } else {
 
1541
# if defined(THREADS) && defined(MPROTECT_VDB)
1520
1542
    GC_push_all_eager(bottom, top);
1521
 
  }
 
1543
# else
 
1544
    if (!NEED_FIXUP_POINTER && GC_all_interior_pointers) {
 
1545
      GC_push_all(bottom, top);
 
1546
    } else {
 
1547
      GC_push_all_eager(bottom, top);
 
1548
    }
 
1549
# endif
1522
1550
}
1523
1551
 
1524
 
#if !defined(SMALL_CONFIG) && !defined(USE_MARK_BYTES)
 
1552
#if !defined(SMALL_CONFIG) && !defined(USE_MARK_BYTES) && \
 
1553
    defined(MARK_BIT_PER_GRANULE)
 
1554
# if GC_GRANULE_WORDS == 1
 
1555
#   define USE_PUSH_MARKED_ACCELERATORS
 
1556
#   define PUSH_GRANULE(q) \
 
1557
                { ptr_t qcontents = (ptr_t)((q)[0]); \
 
1558
                  GC_PUSH_ONE_HEAP(qcontents, (q)); }
 
1559
# elif GC_GRANULE_WORDS == 2
 
1560
#   define USE_PUSH_MARKED_ACCELERATORS
 
1561
#   define PUSH_GRANULE(q) \
 
1562
                { ptr_t qcontents = (ptr_t)((q)[0]); \
 
1563
                  GC_PUSH_ONE_HEAP(qcontents, (q)); \
 
1564
                  qcontents = (ptr_t)((q)[1]); \
 
1565
                  GC_PUSH_ONE_HEAP(qcontents, (q)+1); }
 
1566
# elif GC_GRANULE_WORDS == 4
 
1567
#   define USE_PUSH_MARKED_ACCELERATORS
 
1568
#   define PUSH_GRANULE(q) \
 
1569
                { ptr_t qcontents = (ptr_t)((q)[0]); \
 
1570
                  GC_PUSH_ONE_HEAP(qcontents, (q)); \
 
1571
                  qcontents = (ptr_t)((q)[1]); \
 
1572
                  GC_PUSH_ONE_HEAP(qcontents, (q)+1); \
 
1573
                  qcontents = (ptr_t)((q)[2]); \
 
1574
                  GC_PUSH_ONE_HEAP(qcontents, (q)+2); \
 
1575
                  qcontents = (ptr_t)((q)[3]); \
 
1576
                  GC_PUSH_ONE_HEAP(qcontents, (q)+3); }
 
1577
# endif
 
1578
#endif
 
1579
 
 
1580
#ifdef USE_PUSH_MARKED_ACCELERATORS
1525
1581
/* Push all objects reachable from marked objects in the given block */
1526
 
/* of size 1 objects.                                                */
1527
 
void GC_push_marked1(h, hhdr)
1528
 
struct hblk *h;
1529
 
register hdr * hhdr;
 
1582
/* containing objects of size 1 granule.                             */
 
1583
void GC_push_marked1(struct hblk *h, hdr *hhdr)
1530
1584
{
1531
1585
    word * mark_word_addr = &(hhdr->hb_marks[0]);
1532
 
    register word *p;
 
1586
    word *p;
1533
1587
    word *plim;
1534
 
    register int i;
1535
 
    register word q;
1536
 
    register word mark_word;
1537
 
    register ptr_t greatest_ha = GC_greatest_plausible_heap_addr;
1538
 
    register ptr_t least_ha = GC_least_plausible_heap_addr;
1539
 
    register mse * mark_stack_top = GC_mark_stack_top;
1540
 
    register mse * mark_stack_limit = GC_mark_stack_limit;
 
1588
    word *q;
 
1589
    word mark_word;
 
1590
 
 
1591
    /* Allow registers to be used for some frequently acccessed */
 
1592
    /* global variables.  Otherwise aliasing issues are likely  */
 
1593
    /* to prevent that.                                         */
 
1594
    ptr_t greatest_ha = GC_greatest_plausible_heap_addr;
 
1595
    ptr_t least_ha = GC_least_plausible_heap_addr;
 
1596
    mse * mark_stack_top = GC_mark_stack_top;
 
1597
    mse * mark_stack_limit = GC_mark_stack_limit;
1541
1598
#   define GC_mark_stack_top mark_stack_top
1542
1599
#   define GC_mark_stack_limit mark_stack_limit
1543
1600
#   define GC_greatest_plausible_heap_addr greatest_ha
1549
1606
    /* go through all words in block */
1550
1607
        while( p < plim )  {
1551
1608
            mark_word = *mark_word_addr++;
1552
 
            i = 0;
 
1609
            q = p;
1553
1610
            while(mark_word != 0) {
1554
1611
              if (mark_word & 1) {
1555
 
                  q = p[i];
1556
 
                  GC_PUSH_ONE_HEAP(q, p + i);
 
1612
                  PUSH_GRANULE(q);
1557
1613
              }
1558
 
              i++;
 
1614
              q += GC_GRANULE_WORDS;
1559
1615
              mark_word >>= 1;
1560
1616
            }
1561
 
            p += WORDSZ;
 
1617
            p += WORDSZ*GC_GRANULE_WORDS;
1562
1618
        }
 
1619
 
1563
1620
#   undef GC_greatest_plausible_heap_addr
1564
1621
#   undef GC_least_plausible_heap_addr        
1565
1622
#   undef GC_mark_stack_top
1566
1623
#   undef GC_mark_stack_limit
 
1624
 
1567
1625
    GC_mark_stack_top = mark_stack_top;
1568
1626
}
1569
1627
 
1571
1629
#ifndef UNALIGNED
1572
1630
 
1573
1631
/* Push all objects reachable from marked objects in the given block */
1574
 
/* of size 2 objects.                                                */
1575
 
void GC_push_marked2(h, hhdr)
1576
 
struct hblk *h;
1577
 
register hdr * hhdr;
 
1632
/* of size 2 (granules) objects.                                     */
 
1633
void GC_push_marked2(struct hblk *h, hdr *hhdr)
1578
1634
{
1579
1635
    word * mark_word_addr = &(hhdr->hb_marks[0]);
1580
 
    register word *p;
 
1636
    word *p;
1581
1637
    word *plim;
1582
 
    register int i;
1583
 
    register word q;
1584
 
    register word mark_word;
1585
 
    register ptr_t greatest_ha = GC_greatest_plausible_heap_addr;
1586
 
    register ptr_t least_ha = GC_least_plausible_heap_addr;
1587
 
    register mse * mark_stack_top = GC_mark_stack_top;
1588
 
    register mse * mark_stack_limit = GC_mark_stack_limit;
 
1638
    word *q;
 
1639
    word mark_word;
 
1640
 
 
1641
    ptr_t greatest_ha = GC_greatest_plausible_heap_addr;
 
1642
    ptr_t least_ha = GC_least_plausible_heap_addr;
 
1643
    mse * mark_stack_top = GC_mark_stack_top;
 
1644
    mse * mark_stack_limit = GC_mark_stack_limit;
 
1645
 
1589
1646
#   define GC_mark_stack_top mark_stack_top
1590
1647
#   define GC_mark_stack_limit mark_stack_limit
1591
1648
#   define GC_greatest_plausible_heap_addr greatest_ha
1597
1654
    /* go through all words in block */
1598
1655
        while( p < plim )  {
1599
1656
            mark_word = *mark_word_addr++;
1600
 
            i = 0;
 
1657
            q = p;
1601
1658
            while(mark_word != 0) {
1602
1659
              if (mark_word & 1) {
1603
 
                  q = p[i];
1604
 
                  GC_PUSH_ONE_HEAP(q, p + i);
1605
 
                  q = p[i+1];
1606
 
                  GC_PUSH_ONE_HEAP(q, p + i);
 
1660
                  PUSH_GRANULE(q);
 
1661
                  PUSH_GRANULE(q + GC_GRANULE_WORDS);
1607
1662
              }
1608
 
              i += 2;
 
1663
              q += 2 * GC_GRANULE_WORDS;
1609
1664
              mark_word >>= 2;
1610
1665
            }
1611
 
            p += WORDSZ;
 
1666
            p += WORDSZ*GC_GRANULE_WORDS;
1612
1667
        }
 
1668
 
1613
1669
#   undef GC_greatest_plausible_heap_addr
1614
1670
#   undef GC_least_plausible_heap_addr        
1615
1671
#   undef GC_mark_stack_top
1616
1672
#   undef GC_mark_stack_limit
 
1673
 
1617
1674
    GC_mark_stack_top = mark_stack_top;
1618
1675
}
1619
1676
 
 
1677
# if GC_GRANULE_WORDS < 4
1620
1678
/* Push all objects reachable from marked objects in the given block */
1621
 
/* of size 4 objects.                                                */
 
1679
/* of size 4 (granules) objects.                                     */
1622
1680
/* There is a risk of mark stack overflow here.  But we handle that. */
1623
1681
/* And only unmarked objects get pushed, so it's not very likely.    */
1624
 
void GC_push_marked4(h, hhdr)
1625
 
struct hblk *h;
1626
 
register hdr * hhdr;
 
1682
void GC_push_marked4(struct hblk *h, hdr *hhdr)
1627
1683
{
1628
1684
    word * mark_word_addr = &(hhdr->hb_marks[0]);
1629
 
    register word *p;
 
1685
    word *p;
1630
1686
    word *plim;
1631
 
    register int i;
1632
 
    register word q;
1633
 
    register word mark_word;
1634
 
    register ptr_t greatest_ha = GC_greatest_plausible_heap_addr;
1635
 
    register ptr_t least_ha = GC_least_plausible_heap_addr;
1636
 
    register mse * mark_stack_top = GC_mark_stack_top;
1637
 
    register mse * mark_stack_limit = GC_mark_stack_limit;
 
1687
    word *q;
 
1688
    word mark_word;
 
1689
 
 
1690
    ptr_t greatest_ha = GC_greatest_plausible_heap_addr;
 
1691
    ptr_t least_ha = GC_least_plausible_heap_addr;
 
1692
    mse * mark_stack_top = GC_mark_stack_top;
 
1693
    mse * mark_stack_limit = GC_mark_stack_limit;
1638
1694
#   define GC_mark_stack_top mark_stack_top
1639
1695
#   define GC_mark_stack_limit mark_stack_limit
1640
1696
#   define GC_greatest_plausible_heap_addr greatest_ha
1646
1702
    /* go through all words in block */
1647
1703
        while( p < plim )  {
1648
1704
            mark_word = *mark_word_addr++;
1649
 
            i = 0;
 
1705
            q = p;
1650
1706
            while(mark_word != 0) {
1651
1707
              if (mark_word & 1) {
1652
 
                  q = p[i];
1653
 
                  GC_PUSH_ONE_HEAP(q, p + i);
1654
 
                  q = p[i+1];
1655
 
                  GC_PUSH_ONE_HEAP(q, p + i + 1);
1656
 
                  q = p[i+2];
1657
 
                  GC_PUSH_ONE_HEAP(q, p + i + 2);
1658
 
                  q = p[i+3];
1659
 
                  GC_PUSH_ONE_HEAP(q, p + i + 3);
 
1708
                  PUSH_GRANULE(q);
 
1709
                  PUSH_GRANULE(q + GC_GRANULE_WORDS);
 
1710
                  PUSH_GRANULE(q + 2*GC_GRANULE_WORDS);
 
1711
                  PUSH_GRANULE(q + 3*GC_GRANULE_WORDS);
1660
1712
              }
1661
 
              i += 4;
 
1713
              q += 4 * GC_GRANULE_WORDS;
1662
1714
              mark_word >>= 4;
1663
1715
            }
1664
 
            p += WORDSZ;
 
1716
            p += WORDSZ*GC_GRANULE_WORDS;
1665
1717
        }
1666
1718
#   undef GC_greatest_plausible_heap_addr
1667
1719
#   undef GC_least_plausible_heap_addr        
1670
1722
    GC_mark_stack_top = mark_stack_top;
1671
1723
}
1672
1724
 
 
1725
#endif /* GC_GRANULE_WORDS < 4 */
 
1726
 
1673
1727
#endif /* UNALIGNED */
1674
1728
 
1675
 
#endif /* SMALL_CONFIG */
 
1729
#endif /* USE_PUSH_MARKED_ACCELERATORS */
1676
1730
 
1677
1731
/* Push all objects reachable from marked objects in the given block */
1678
 
void GC_push_marked(h, hhdr)
1679
 
struct hblk *h;
1680
 
register hdr * hhdr;
 
1732
void GC_push_marked(struct hblk *h, hdr *hhdr)
1681
1733
{
1682
 
    register int sz = hhdr -> hb_sz;
1683
 
    register int descr = hhdr -> hb_descr;
1684
 
    register word * p;
1685
 
    register int word_no;
1686
 
    register word * lim;
1687
 
    register mse * GC_mark_stack_top_reg;
1688
 
    register mse * mark_stack_limit = GC_mark_stack_limit;
 
1734
    size_t sz = hhdr -> hb_sz;
 
1735
    word descr = hhdr -> hb_descr;
 
1736
    ptr_t p;
 
1737
    word bit_no;
 
1738
    ptr_t lim;
 
1739
    mse * GC_mark_stack_top_reg;
 
1740
    mse * mark_stack_limit = GC_mark_stack_limit;
1689
1741
    
1690
1742
    /* Some quick shortcuts: */
1691
1743
        if ((0 | GC_DS_LENGTH) == descr) return;
1692
1744
        if (GC_block_empty(hhdr)/* nothing marked */) return;
1693
1745
    GC_n_rescuing_pages++;
1694
1746
    GC_objects_are_marked = TRUE;
1695
 
    if (sz > MAXOBJSZ) {
1696
 
        lim = (word *)h;
 
1747
    if (sz > MAXOBJBYTES) {
 
1748
        lim = h -> hb_body;
1697
1749
    } else {
1698
 
        lim = (word *)(h + 1) - sz;
 
1750
        lim = (h + 1)->hb_body - sz;
1699
1751
    }
1700
1752
    
1701
 
    switch(sz) {
1702
 
#   if !defined(SMALL_CONFIG) && !defined(USE_MARK_BYTES)   
 
1753
    switch(BYTES_TO_GRANULES(sz)) {
 
1754
#   if defined(USE_PUSH_MARKED_ACCELERATORS)
1703
1755
     case 1:
1704
1756
       GC_push_marked1(h, hhdr);
1705
1757
       break;
1706
 
#   endif
1707
 
#   if !defined(SMALL_CONFIG) && !defined(UNALIGNED) && \
1708
 
       !defined(USE_MARK_BYTES)
1709
 
     case 2:
1710
 
       GC_push_marked2(h, hhdr);
1711
 
       break;
1712
 
     case 4:
1713
 
       GC_push_marked4(h, hhdr);
1714
 
       break;
 
1758
#    if !defined(UNALIGNED)
 
1759
       case 2:
 
1760
         GC_push_marked2(h, hhdr);
 
1761
         break;
 
1762
#     if GC_GRANULE_WORDS < 4
 
1763
       case 4:
 
1764
         GC_push_marked4(h, hhdr);
 
1765
         break;
 
1766
#     endif
 
1767
#    endif
1715
1768
#   endif       
1716
1769
     default:
1717
1770
      GC_mark_stack_top_reg = GC_mark_stack_top;
1718
 
      for (p = (word *)h, word_no = 0; p <= lim; p += sz, word_no += sz) {
1719
 
         if (mark_bit_from_hdr(hhdr, word_no)) {
 
1771
      for (p = h -> hb_body, bit_no = 0; p <= lim;
 
1772
           p += sz, bit_no += MARK_BIT_OFFSET(sz)) {
 
1773
         if (mark_bit_from_hdr(hhdr, bit_no)) {
1720
1774
           /* Mark from fields inside the object */
1721
 
             PUSH_OBJ((word *)p, hhdr, GC_mark_stack_top_reg, mark_stack_limit);
1722
 
#            ifdef GATHERSTATS
1723
 
                /* Subtract this object from total, since it was        */
1724
 
                /* added in twice.                                      */
1725
 
                GC_composite_in_use -= sz;
1726
 
#            endif
 
1775
             PUSH_OBJ(p, hhdr, GC_mark_stack_top_reg, mark_stack_limit);
1727
1776
         }
1728
1777
      }
1729
1778
      GC_mark_stack_top = GC_mark_stack_top_reg;
1732
1781
 
1733
1782
#ifndef SMALL_CONFIG
1734
1783
/* Test whether any page in the given block is dirty    */
1735
 
GC_bool GC_block_was_dirty(h, hhdr)
1736
 
struct hblk *h;
1737
 
register hdr * hhdr;
 
1784
GC_bool GC_block_was_dirty(struct hblk *h, hdr *hhdr)
1738
1785
{
1739
 
    register int sz = hhdr -> hb_sz;
 
1786
    size_t sz = hhdr -> hb_sz;
1740
1787
    
1741
 
    if (sz <= MAXOBJSZ) {
 
1788
    if (sz <= MAXOBJBYTES) {
1742
1789
         return(GC_page_was_dirty(h));
1743
1790
    } else {
1744
 
         register ptr_t p = (ptr_t)h;
1745
 
         sz = WORDS_TO_BYTES(sz);
 
1791
         ptr_t p = (ptr_t)h;
1746
1792
         while (p < (ptr_t)h + sz) {
1747
1793
             if (GC_page_was_dirty((struct hblk *)p)) return(TRUE);
1748
1794
             p += HBLKSIZE;
1752
1798
}
1753
1799
#endif /* SMALL_CONFIG */
1754
1800
 
1755
 
/* Similar to GC_push_next_marked, but return address of next block     */
1756
 
struct hblk * GC_push_next_marked(h)
1757
 
struct hblk *h;
 
1801
/* Similar to GC_push_marked, but skip over unallocated blocks  */
 
1802
/* and return address of next plausible block.                  */
 
1803
struct hblk * GC_push_next_marked(struct hblk *h)
1758
1804
{
1759
 
    register hdr * hhdr;
 
1805
    hdr * hhdr = HDR(h);
1760
1806
    
1761
 
    h = GC_next_used_block(h);
1762
 
    if (h == 0) return(0);
1763
 
    hhdr = HDR(h);
 
1807
    if (EXPECT(IS_FORWARDING_ADDR_OR_NIL(hhdr), FALSE)) {
 
1808
      h = GC_next_used_block(h);
 
1809
      if (h == 0) return(0);
 
1810
      hhdr = GC_find_header((ptr_t)h);
 
1811
    }
1764
1812
    GC_push_marked(h, hhdr);
1765
1813
    return(h + OBJ_SZ_TO_BLOCKS(hhdr -> hb_sz));
1766
1814
}
1767
1815
 
1768
1816
#ifndef SMALL_CONFIG
1769
1817
/* Identical to above, but mark only from dirty pages   */
1770
 
struct hblk * GC_push_next_marked_dirty(h)
1771
 
struct hblk *h;
 
1818
struct hblk * GC_push_next_marked_dirty(struct hblk *h)
1772
1819
{
1773
 
    register hdr * hhdr;
 
1820
    hdr * hhdr = HDR(h);
1774
1821
    
1775
1822
    if (!GC_dirty_maintained) { ABORT("dirty bits not set up"); }
1776
1823
    for (;;) {
1777
 
        h = GC_next_used_block(h);
1778
 
        if (h == 0) return(0);
1779
 
        hhdr = HDR(h);
 
1824
        if (EXPECT(IS_FORWARDING_ADDR_OR_NIL(hhdr), FALSE)) {
 
1825
          h = GC_next_used_block(h);
 
1826
          if (h == 0) return(0);
 
1827
          hhdr = GC_find_header((ptr_t)h);
 
1828
        }
1780
1829
#       ifdef STUBBORN_ALLOC
1781
1830
          if (hhdr -> hb_obj_kind == STUBBORN) {
1782
1831
            if (GC_page_was_changed(h) && GC_block_was_dirty(h, hhdr)) {
1789
1838
          if (GC_block_was_dirty(h, hhdr)) break;
1790
1839
#       endif
1791
1840
        h += OBJ_SZ_TO_BLOCKS(hhdr -> hb_sz);
 
1841
        hhdr = HDR(h);
1792
1842
    }
1793
1843
    GC_push_marked(h, hhdr);
1794
1844
    return(h + OBJ_SZ_TO_BLOCKS(hhdr -> hb_sz));
1797
1847
 
1798
1848
/* Similar to above, but for uncollectable pages.  Needed since we      */
1799
1849
/* do not clear marks for such pages, even for full collections.        */
1800
 
struct hblk * GC_push_next_marked_uncollectable(h)
1801
 
struct hblk *h;
 
1850
struct hblk * GC_push_next_marked_uncollectable(struct hblk *h)
1802
1851
{
1803
 
    register hdr * hhdr = HDR(h);
 
1852
    hdr * hhdr = HDR(h);
1804
1853
    
1805
1854
    for (;;) {
1806
 
        h = GC_next_used_block(h);
1807
 
        if (h == 0) return(0);
1808
 
        hhdr = HDR(h);
 
1855
        if (EXPECT(IS_FORWARDING_ADDR_OR_NIL(hhdr), FALSE)) {
 
1856
          h = GC_next_used_block(h);
 
1857
          if (h == 0) return(0);
 
1858
          hhdr = GC_find_header((ptr_t)h);
 
1859
        }
1809
1860
        if (hhdr -> hb_obj_kind == UNCOLLECTABLE) break;
1810
1861
        h += OBJ_SZ_TO_BLOCKS(hhdr -> hb_sz);
 
1862
        hhdr = HDR(h);
1811
1863
    }
1812
1864
    GC_push_marked(h, hhdr);
1813
1865
    return(h + OBJ_SZ_TO_BLOCKS(hhdr -> hb_sz));
1814
1866
}
1815
1867
 
1816