Transpose lines.
[sbcl.git] / tests / gc-testlib.c
blobddbdefaf5d53105b044d0b874499a9c344673b60
1 /* Test that layout pointer in a compact instance header
2 * isn't overlooked by scan_boxed_root_cards_spanning()
3 * or update_writeprotection() */
5 #include <stdio.h>
6 #include "genesis/sbcl.h"
7 #include "gc.h"
8 #include "genesis/instance.h"
9 #include "thread.h"
11 extern struct generation generations[];
12 extern os_vm_size_t bytes_allocated;
14 // Create a 2-word instance and a 6-word funcallable instance.
15 // Ensure they are on different GC cards.
16 static void make_instances(int page_type, generation_index_t gen, lispobj result[2])
18 page_index_t page = 0, last;
19 // Passing SINGLE_OBJECT_FLAG avoids combining with a previous page
20 last = gc_find_freeish_pages(&page, GENCGC_PAGE_BYTES,
21 SINGLE_OBJECT_FLAG | page_type, gen);
22 gc_assert(last == page);
23 lispobj* where = (void*)page_address(page);
24 page_table[page].type = page_type;
25 page_table[page].gen = 1;
26 gc_assert(page_table[page].scan_start_offset_ == 0);
27 page_table[page].words_used_ = (2 * GENCGC_CARD_BYTES) >> WORD_SHIFT;
28 page_table[page].need_zerofill = 1;
29 bytes_allocated += 2 * GENCGC_CARD_BYTES;
30 generations[gen].bytes_allocated += 2 * GENCGC_CARD_BYTES;
32 // Create the ordinary instance, total length 2 words
33 lispobj instance = make_lispobj(where, INSTANCE_POINTER_LOWTAG);
34 where[0] = (1 << INSTANCE_LENGTH_SHIFT) | INSTANCE_WIDETAG;
35 where[1] = 0;
36 where += 2;
38 // Fill to the end of the card
39 int filler_nwords = (GENCGC_CARD_BYTES >> WORD_SHIFT) - 2;
40 *where = make_filler_header(filler_nwords);
42 // Assert that no tagged pointer can point to the filler
43 // fprintf(stderr, "Filler @ %p: %"OBJ_FMTX"\n", where, *where);
44 int lowtag;
45 for (lowtag=1; lowtag<=LOWTAG_MASK; ++lowtag) {
46 lispobj addr = make_lispobj(where, lowtag);
47 gc_assert(!plausible_tag_p(addr));
50 where += filler_nwords;
52 // Create the funcallable instance, total length 6 words
53 lispobj funinstance = make_lispobj(where, FUN_POINTER_LOWTAG);
54 where[0] = (1 << N_WIDETAG_BITS) | FUNCALLABLE_INSTANCE_WIDETAG;
55 where[1] = where[2] = where[3] = where[4] = where[5] = 0;
56 where += 6;
58 // Fill to the end of the card
59 filler_nwords = (GENCGC_CARD_BYTES >> WORD_SHIFT) - 6;
60 *where = make_filler_header(filler_nwords);
61 where += filler_nwords;
63 result[0] = instance;
64 result[1] = funinstance;
67 static void perform_gc(lispobj* stackptr)
69 extern void close_current_thread_tlab();
70 extern void garbage_collect_generation(generation_index_t, int, void*);
72 gc_active_p = 1;
73 gc_close_collector_regions(0); // TODO: should be THREAD_PAGE_FLAG
74 close_current_thread_tlab();
76 /* We have to clobber the dynamic space codeblob tree because ordinarily
77 * it gets smashed at the start of collect_garbage(), and since this test
78 * bypasses collect_garbage(), the GC might have problems later.
79 * (Not exactly sure how, but "header not OK for code page" was triggering)
80 * So, handily, since there are no concurrency issues in this test,
81 * it doesn't matter that the GC can't utilize the tree. It falls back
82 * to scanning code pages linearly in preserve_pointer which is fine. */
83 SYMBOL(DYNSPACE_CODEBLOB_TREE)->value = NIL;
85 verify_heap(stackptr, VERIFY_PRE_GC);
86 garbage_collect_generation(0, 0, stackptr);
87 gc_active_p = 0;
90 void run_cardmark_test(int page_type,
91 lispobj young_layout, lispobj old_layout,
92 lispobj* stackptr)
94 lispobj instances[2];
95 make_instances(page_type, 1, instances);
96 lispobj instance = instances[0], funinstance = instances[1];
97 fprintf(stderr, "allocated @ %p and %p\n", (void*)instance, (void*)funinstance);
98 long instance_card = addr_to_card_index((void*)instance);
99 long funinstance_card = addr_to_card_index((void*)funinstance);
101 // Assert something about the card indices
102 fprintf(stderr, "page = %d, cards = %d and %d\n",
103 (int)find_page_index((void*)instance),
104 (int)instance_card, (int)funinstance_card);
105 gc_assert(funinstance_card == instance_card+1);
107 perform_gc(stackptr);
108 // the cards containing the instances should be unmarked
109 gc_assert(gc_card_mark[instance_card] == CARD_UNMARKED);
110 gc_assert(gc_card_mark[funinstance_card] == CARD_UNMARKED);
111 instance_layout(native_pointer(instance)) = old_layout;
112 instance_layout(native_pointer(funinstance)) = old_layout;
113 gc_card_mark[instance_card] = CARD_MARKED;
114 gc_card_mark[funinstance_card] = CARD_MARKED;
115 perform_gc(stackptr);
116 // should have gotten unmarked
117 gc_assert(gc_card_mark[instance_card] == CARD_UNMARKED);
118 gc_assert(gc_card_mark[funinstance_card] == CARD_UNMARKED);
120 // Test 1: regular instance
121 instance_layout(native_pointer(instance)) = young_layout;
122 gc_card_mark[instance_card] = CARD_MARKED;
123 gc_card_mark[funinstance_card] = CARD_MARKED; // "spuriously" marked
124 perform_gc(stackptr);
125 // should stay marked
126 gc_assert(gc_card_mark[instance_card] == CARD_MARKED);
127 // BOXED pages can undirty at the card granularity, but MIXED pages can't
128 if (page_type == PAGE_TYPE_BOXED)
129 gc_assert(gc_card_mark[funinstance_card] == CARD_UNMARKED);
131 instance_layout(native_pointer(instance)) = old_layout;
132 perform_gc(stackptr);
133 // both cards are clean
134 gc_assert(gc_card_mark[instance_card] == CARD_UNMARKED);
135 gc_assert(gc_card_mark[funinstance_card] == CARD_UNMARKED);
137 // Test 2: funinstance
138 instance_layout(native_pointer(funinstance)) = young_layout;
139 gc_card_mark[funinstance_card] = CARD_MARKED;
140 gc_card_mark[instance_card] = CARD_MARKED; // "spuriously" marked
141 perform_gc(stackptr);
142 // should stay marked
143 gc_assert(gc_card_mark[funinstance_card] == CARD_MARKED);
144 // BOXED pages can undirty at the card granularity, but MIXED pages can't
145 if (page_type == PAGE_TYPE_BOXED)
146 gc_assert(gc_card_mark[instance_card] == CARD_UNMARKED);
148 funinstance_layout(native_pointer(funinstance)) = old_layout;
149 perform_gc(stackptr);
150 // both cards are clean
151 gc_assert(gc_card_mark[instance_card] == CARD_UNMARKED);
152 gc_assert(gc_card_mark[funinstance_card] == CARD_UNMARKED);
153 printf("PASS\n");
156 int compact_instance_layout_pointer_test(lispobj arg)
158 // Capture the approximate stack pointer on entry
159 lispobj* stackptr = &arg;
160 struct vector* layouts = (void*)native_pointer(arg);
161 lispobj young_layout = layouts->data[0];
162 lispobj old_layout = layouts->data[1];
163 gc_assert(immobile_obj_generation(native_pointer(young_layout))==0);
164 // Don't want sticky marks messing up the test.
165 // It suffices to check that there are no register contexts.
166 struct thread* self = get_sb_vm_thread();
167 gc_assert(read_TLS(FREE_INTERRUPT_CONTEXT_INDEX, self) == 0);
168 printf("PAGE_TYPE_MIXED:\n"); fflush(stdout);
169 run_cardmark_test(PAGE_TYPE_MIXED, young_layout, old_layout, stackptr);
170 printf("PAGE_TYPE_BOXED:\n"); fflush(stdout);
171 run_cardmark_test(PAGE_TYPE_BOXED, young_layout, old_layout, stackptr);
172 return 0;