1 /* Test that layout pointer in a compact instance header
2 * isn't overlooked by scan_boxed_root_cards_spanning()
3 * or update_writeprotection() */
6 #include "genesis/sbcl.h"
8 #include "genesis/instance.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
;
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);
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;
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
;
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*);
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
);
90 void run_cardmark_test(int page_type
,
91 lispobj young_layout
, lispobj old_layout
,
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
);
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
);