Raymond Toy pushed to branch issue-243-weak-pointer-to-static-array at cmucl / cmucl

Commits:

1 changed file:

Changes:

  • src/lisp/gencgc.c
    ... ... @@ -2130,6 +2130,7 @@ static lispobj(*transother[256]) (lispobj object);
    2130 2130
     static int (*sizetab[256]) (lispobj * where);
    
    2131 2131
     
    
    2132 2132
     static struct weak_pointer *weak_pointers;
    
    2133
    +static struct weak_pointer *inuse_static_vector_list;
    
    2133 2134
     static struct scavenger_hook *scavenger_hooks = (struct scavenger_hook *) NIL;
    
    2134 2135
     
    
    2135 2136
     /* Like (ceiling x y), but y is constrained to be a power of two */
    
    ... ... @@ -2734,7 +2735,7 @@ scav_static_vector(lispobj object)
    2734 2735
             int static_p;
    
    2735 2736
     
    
    2736 2737
             if (debug_static_array_p) {
    
    2737
    -            fprintf(stderr, "Possible static vector at %p.  header = 0x%08lx\n",
    
    2738
    +            fprintf(stderr, "Possible static vector at %p.  header = 0x%lx\n",
    
    2738 2739
                         ptr, (unsigned long) header);
    
    2739 2740
             }
    
    2740 2741
     
    
    ... ... @@ -2745,9 +2746,9 @@ scav_static_vector(lispobj object)
    2745 2746
                  * setting the MSB of the header.  And clear out any
    
    2746 2747
                  * possible visited bit.
    
    2747 2748
                  */
    
    2748
    -            *ptr = (header | STATIC_VECTOR_MARK_BIT);
    
    2749
    +            *ptr = (header | STATIC_VECTOR_MARK_BIT) & ~STATIC_VECTOR_VISITED_BIT;
    
    2749 2750
                 if (debug_static_array_p) {
    
    2750
    -                fprintf(stderr, "Scavenged static vector @%p, header = 0x%08lx\n",
    
    2751
    +                fprintf(stderr, "Scavenged static vector @%p, header = 0x%lx\n",
    
    2751 2752
                             ptr, (unsigned long) header);
    
    2752 2753
                 }
    
    2753 2754
             }
    
    ... ... @@ -5388,14 +5389,6 @@ scav_weak_pointer(lispobj * where, lispobj object)
    5388 5389
         struct weak_pointer *this_wp = (struct weak_pointer *) where;
    
    5389 5390
     
    
    5390 5391
         if (this_wp->mark_bit == NIL) {
    
    5391
    -        lispobj *header = (lispobj *) PTR(this_wp->value);
    
    5392
    -        if (maybe_static_array_p(*header)) {
    
    5393
    -            printf("Scavenge wp %p to static array %p header 0x%08lx\n",
    
    5394
    -                   this_wp, (lispobj *) this_wp->value, *header);
    
    5395
    -
    
    5396
    -            *header &= ~STATIC_VECTOR_VISITED_BIT;
    
    5397
    -        }
    
    5398
    -
    
    5399 5392
     	this_wp->mark_bit = T;
    
    5400 5393
     	this_wp->next = weak_pointers;
    
    5401 5394
     	weak_pointers = this_wp;
    
    ... ... @@ -5449,14 +5442,16 @@ push_weak_pointer(struct weak_pointer* wp, struct weak_pointer **list)
    5449 5442
     }
    
    5450 5443
     
    
    5451 5444
     /*
    
    5452
    - * Phase 2: Process the list of weak pointers to unused static
    
    5453
    - * vectors.  We find the unique static vectors and add each
    
    5454
    - * corresponding weak pointer to freeable_list.  For the duplicates,
    
    5455
    - * the weak pointer is broken.
    
    5445
    + * Phase 2: Find the weak pointers to static vectors that are in use
    
    5446
    + * and not in use.  The vectors that are in use are added to
    
    5447
    + * inuse_list.  Those that are not in use are added to freeable_list.
    
    5448
    + * Only unique vectors are added to freeable list; a duplicate has its
    
    5449
    + * weak pointer to it broken.
    
    5456 5450
      */
    
    5457 5451
     static void
    
    5458 5452
     scan_static_vectors_2(struct weak_pointer *static_vector_list,
    
    5459
    -                      struct weak_pointer **freeable_list)
    
    5453
    +                      struct weak_pointer **freeable_list,
    
    5454
    +                      struct weak_pointer **inuse_list)
    
    5460 5455
     {
    
    5461 5456
         DPRINTF(debug_static_array_p,
    
    5462 5457
                 (stdout, "Phase 2: Find unused and unused static vectors\n"));
    
    ... ... @@ -5473,23 +5468,34 @@ scan_static_vectors_2(struct weak_pointer *static_vector_list,
    5473 5468
                     (stdout, "  wp %p value %p header 0x%08lx\n",
    
    5474 5469
                      wp, (lispobj *) wp->value, *header));
    
    5475 5470
     
    
    5476
    -        /*
    
    5477
    -         * If we haven't seen this vector before, set the visited flag
    
    5478
    -         * and add it to freeable_list.  If we have visited this
    
    5479
    -         * vector before, break the weak pointer.
    
    5480
    -         */
    
    5481
    -        if ((*header & STATIC_VECTOR_VISITED_BIT) == 0) {
    
    5471
    +        if ((*header & STATIC_VECTOR_MARK_BIT) != 0) {
    
    5472
    +            /*
    
    5473
    +             * Static vector is in use.  Add this to the in-use list.
    
    5474
    +             */
    
    5482 5475
                 DPRINTF(debug_static_array_p,
    
    5483
    -                    (stdout, "    Visit unused vector, add to freeable list\n"));
    
    5476
    +                    (stdout, "    In-use vector; add to in-use list\n"));
    
    5484 5477
     
    
    5485
    -            *header |= STATIC_VECTOR_VISITED_BIT;
    
    5486
    -            push_weak_pointer(wp, freeable_list);
    
    5478
    +            push_weak_pointer(wp, inuse_list);
    
    5487 5479
             } else {
    
    5488
    -            DPRINTF(debug_static_array_p,
    
    5489
    -                    (stdout, "    Already visited unused vector; break weak pointer\n"));
    
    5480
    +            /*
    
    5481
    +             * Static vector not in use.  If we haven't seen this
    
    5482
    +             * vector before, set the visited flag and add it to
    
    5483
    +             * freeable_list.  If we have visited this vector before,
    
    5484
    +             * break the weak pointer.
    
    5485
    +             */
    
    5486
    +            if ((*header & STATIC_VECTOR_VISITED_BIT) == 0) {
    
    5487
    +                DPRINTF(debug_static_array_p,
    
    5488
    +                        (stdout, "    Visit unused vector, add to freeable list\n"));
    
    5490 5489
     
    
    5491
    -            wp->value = NIL;
    
    5492
    -            wp->broken = T;
    
    5490
    +                *header |= STATIC_VECTOR_VISITED_BIT;
    
    5491
    +                push_weak_pointer(wp, freeable_list);
    
    5492
    +            } else {
    
    5493
    +                DPRINTF(debug_static_array_p,
    
    5494
    +                        (stdout, "    Already visited unused vector; break weak pointer\n"));
    
    5495
    +
    
    5496
    +                wp->value = NIL;
    
    5497
    +                wp->broken = T;
    
    5498
    +            }
    
    5493 5499
             }
    
    5494 5500
         }
    
    5495 5501
     
    
    ... ... @@ -5512,15 +5518,18 @@ scan_static_vectors_3(struct weak_pointer *freeable_list)
    5512 5518
             lispobj *header = (lispobj *) PTR(wp->value);
    
    5513 5519
             lispobj *static_array = (lispobj *) PTR(wp->value);
    
    5514 5520
     
    
    5521
    +        /*
    
    5522
    +         * Invariant: weak pointer must not be broken
    
    5523
    +         */
    
    5524
    +        gc_assert(wp->broken == NIL);
    
    5525
    +
    
    5515 5526
             DPRINTF(debug_static_array_p,
    
    5516 5527
                     (stdout, "  wp %p value %p header 0x%08lx\n",
    
    5517 5528
                      wp, (lispobj*) wp->value, *header));
    
    5518 5529
     
    
    5519 5530
             /*
    
    5520
    -         * Invariants: weak pointer must not be broken and the mark
    
    5521
    -         * bit must be clear.
    
    5531
    +         * Invariant: Mark bit must be clear
    
    5522 5532
              */
    
    5523
    -        gc_assert(wp->broken == NIL);
    
    5524 5533
             gc_assert(((*header & STATIC_VECTOR_MARK_BIT) == 0));
    
    5525 5534
     
    
    5526 5535
             DPRINTF(debug_static_array_p,
    
    ... ... @@ -5536,6 +5545,49 @@ scan_static_vectors_3(struct weak_pointer *freeable_list)
    5536 5545
                 (stdout, "Phase 3 done\n"));
    
    5537 5546
     }
    
    5538 5547
     
    
    5548
    +/*
    
    5549
    + * Unmark all the vectors in inuse_list.  This needs to be called at
    
    5550
    + * the end of GC to unmark any live static vectors so that for the
    
    5551
    + * next GC we can tell if the static vector is used or not.
    
    5552
    + * Otherwise, the vectors will always look as if they're in use
    
    5553
    + * because the mark bit is never changed.
    
    5554
    + */
    
    5555
    +static void
    
    5556
    +unmark_static_vectors_in_use(struct weak_pointer *inuse_list)
    
    5557
    +{
    
    5558
    +    struct weak_pointer *wp;
    
    5559
    +
    
    5560
    +    DPRINTF(debug_static_array_p,
    
    5561
    +            (stdout, "Phase 4: unmark static vectors\n"));
    
    5562
    +
    
    5563
    +    for (wp = inuse_list; wp; wp = wp->next) {
    
    5564
    +        lispobj *header = (lispobj *) PTR(wp->value);
    
    5565
    +        /*
    
    5566
    +         * Invariant: the weak pointer must not be broken.
    
    5567
    +         *
    
    5568
    +         * Note that we can't assert that the static vector is marked
    
    5569
    +         * because we can have more than one weak pointer to the same
    
    5570
    +         * static vector.
    
    5571
    +         */
    
    5572
    +        gc_assert(wp->broken == NIL);
    
    5573
    +        
    
    5574
    +        DPRINTF(debug_static_array_p,
    
    5575
    +                (stdout, "  wp %p value %p broken %d header 0x%08lx\n",
    
    5576
    +                 wp, (lispobj*) wp->value, wp->broken == T, *header));
    
    5577
    +
    
    5578
    +        /* Only clear if we haven't already */
    
    5579
    +        if ((*header & STATIC_VECTOR_MARK_BIT) != 0) {
    
    5580
    +            DPRINTF(debug_static_array_p,
    
    5581
    +                    (stdout, "    Clearing mark bit\n"));
    
    5582
    +
    
    5583
    +            *header &= ~STATIC_VECTOR_MARK_BIT;
    
    5584
    +        }
    
    5585
    +    }
    
    5586
    +
    
    5587
    +    DPRINTF(debug_static_array_p,
    
    5588
    +            (stdout, "Phase 4 done\n"));
    
    5589
    +}
    
    5590
    +
    
    5539 5591
     static void
    
    5540 5592
     scan_static_vectors(struct weak_pointer *static_vector_list)
    
    5541 5593
     {
    
    ... ... @@ -5543,10 +5595,11 @@ scan_static_vectors(struct weak_pointer *static_vector_list)
    5543 5595
         struct weak_pointer *freeable_list = NULL;
    
    5544 5596
     
    
    5545 5597
         /*
    
    5546
    -     * For each weak pointer, either break it, or add it to the
    
    5547
    -     * freeable list because it points to a unique static vector.
    
    5598
    +     * For each weak pointer, add it either the inuse list or the
    
    5599
    +     * freeable list.
    
    5548 5600
          */
    
    5549
    -    scan_static_vectors_2(static_vector_list, &freeable_list);
    
    5601
    +    inuse_static_vector_list = NULL;
    
    5602
    +    scan_static_vectors_2(static_vector_list, &freeable_list, &inuse_static_vector_list);
    
    5550 5603
     
    
    5551 5604
         /* Free the unused unique static vectors. */
    
    5552 5605
         scan_static_vectors_3(freeable_list);
    
    ... ... @@ -5564,18 +5617,15 @@ scan_weak_pointers(void)
    5564 5617
          *
    
    5565 5618
          * Also find any weak pointers to static vectors.  This
    
    5566 5619
          * destructively modifies the next slot of the weak pointer to
    
    5567
    -     * chain all the weak pointers to unused static vectors together.
    
    5620
    +     * chain all the weak pointers to static vectors together.
    
    5568 5621
          */
    
    5569 5622
         DPRINTF(debug_static_array_p,
    
    5570 5623
                 (stdout, "Phase 1: Process weak pointers\n"));
    
    5571 5624
     
    
    5572
    -    while (weak_pointers) {
    
    5573
    -	lispobj value;
    
    5574
    -	lispobj *first_pointer;
    
    5575
    -
    
    5576
    -        wp = pop_weak_pointer(&weak_pointers);
    
    5577
    -	value = wp->value;
    
    5578
    -	first_pointer = (lispobj *) PTR(value);
    
    5625
    +    while (wp) {
    
    5626
    +        struct weak_pointer *next = wp->next;
    
    5627
    +	lispobj value = wp->value;
    
    5628
    +	lispobj *first_pointer = (lispobj *) PTR(value);
    
    5579 5629
     
    
    5580 5630
     	wp->mark_bit = NIL;
    
    5581 5631
     	if (Pointerp(value)) {
    
    ... ... @@ -5588,29 +5638,23 @@ scan_weak_pointers(void)
    5588 5638
                     }
    
    5589 5639
                 } else {
    
    5590 5640
                     /* The value may be a static vector */
    
    5591
    -                lispobj *header = (lispobj *) PTR(value);
    
    5592
    -
    
    5593
    -                if (maybe_static_array_p(*header)) {
    
    5594
    -                    if (*header & STATIC_VECTOR_MARK_BIT) {
    
    5595
    -                        DPRINTF(debug_static_array_p,
    
    5596
    -                                (stdout, "  Update status bits for live vector: wp %p value %p header 0x%08lx\n",
    
    5597
    -                                 wp, (lispobj *) wp->value, *header));
    
    5598
    -                        *header = (*header & ~STATIC_VECTOR_MARK_BIT) | STATIC_VECTOR_VISITED_BIT;
    
    5599
    -                    } else if ((*header & STATIC_VECTOR_VISITED_BIT) == 0) {
    
    5600
    -                        /* Only add the vector if it is unmarked and has not been visited */
    
    5601
    -                        DPRINTF(debug_static_array_p,
    
    5602
    -                                (stdout, "  Add static vector:  wp %p value %p header 0x%08lx\n",
    
    5603
    -                                 wp, (lispobj *) wp->value, *header));
    
    5604
    -
    
    5605
    -                        push_weak_pointer(wp, &static_vector_list);
    
    5606
    -                    }
    
    5641
    +                lispobj header = *(lispobj *) PTR(value);
    
    5642
    +
    
    5643
    +                if (maybe_static_array_p(header)) {
    
    5644
    +
    
    5645
    +                    DPRINTF(debug_static_array_p,
    
    5646
    +                            (stdout, "  Add static vector:  wp %p value %p header 0x%08lx\n",
    
    5647
    +                             wp, (lispobj *) wp->value, header));
    
    5648
    +
    
    5649
    +                    push_weak_pointer(wp, &static_vector_list);
    
    5607 5650
                     } else {
    
    5608 5651
                         DPRINTF(debug_static_array_p,
    
    5609 5652
                                 (stdout, "  Skip: wp %p value %p header 0x%08lx\n",
    
    5610
    -                             wp, (lispobj *) wp->value, *header));
    
    5653
    +                             wp, (lispobj *) wp->value, header));
    
    5611 5654
                     }
    
    5612 5655
                 }
    
    5613 5656
             }
    
    5657
    +        wp = next;
    
    5614 5658
         }
    
    5615 5659
     
    
    5616 5660
         scan_static_vectors(static_vector_list);
    
    ... ... @@ -8346,6 +8390,13 @@ collect_garbage(unsigned last_gen)
    8346 8390
     	}
    
    8347 8391
     	scavenger_hooks = (struct scavenger_hook *) NIL;
    
    8348 8392
         }
    
    8393
    +
    
    8394
    +    /*
    
    8395
    +     * Unmark any live static vectors.  This needs to be done at the
    
    8396
    +     * very end when all GCs are done, lest we accidentally free a
    
    8397
    +     * static vector that was actually in use.
    
    8398
    +     */
    
    8399
    +    unmark_static_vectors_in_use(inuse_static_vector_list);
    
    8349 8400
     }
    
    8350 8401
     
    
    8351 8402