3 /* Size sans alignment. */
4 template <typename Fixup>
5 cell object::base_size(Fixup fixup) const {
8 return array_size((array*)this);
10 return array_size((bignum*)this);
12 return array_size((byte_array*)this);
14 return string_size(string_capacity((string*)this));
16 tuple_layout* layout = (tuple_layout*)fixup.translate_data(
17 untag<object>(((tuple*)this)->layout));
18 return tuple_size(layout);
21 return sizeof(quotation);
25 return sizeof(boxed_float);
31 return sizeof(wrapper);
32 case CALLSTACK_TYPE: {
33 return callstack_object_size(untag_fixnum(((callstack*)this)->length));
36 critical_error("Invalid header in base_size", (cell)this);
41 /* Size of the object pointed to by an untagged pointer */
42 template <typename Fixup>
43 cell object::size(Fixup fixup) const {
45 return ((free_heap_block*)this)->size();
46 return align(base_size(fixup), data_alignment);
49 inline cell object::size() const { return size(no_fixup()); }
51 /* The number of slots (cells) in an object which should be scanned by
52 the GC. The number can vary in arrays and tuples, in all other
53 types the number is a constant. */
54 template <typename Fixup>
55 inline cell object::slot_count(Fixup fixup) const {
60 if (t == ARRAY_TYPE) {
61 /* capacity + n slots */
62 return 1 + array_capacity((array*)this);
63 } else if (t == TUPLE_TYPE) {
64 tuple_layout* layout = (tuple_layout*)fixup.translate_data(
65 untag<object>(((tuple*)this)->layout));
66 /* layout + n slots */
67 return 1 + tuple_capacity(layout);
70 /* these objects do not refer to other objects at all */
74 case CALLSTACK_TYPE: return 0;
75 case WORD_TYPE: return 8;
76 case ALIEN_TYPE: return 2;
77 case DLL_TYPE: return 1;
78 case QUOTATION_TYPE: return 3;
79 case STRING_TYPE: return 3;
80 case WRAPPER_TYPE: return 1;
82 critical_error("Invalid header in slot_count", (cell)this);
83 return 0; /* can't happen */
88 inline cell object::slot_count() const {
89 return slot_count(no_fixup());
92 /* Slot visitors iterate over the slots of an object, applying a functor to
93 each one that is a non-immediate slot. The pointer is untagged first. The
94 functor returns a new untagged object pointer. The return value may or may not
96 however the new pointer receives the same tag before being stored back to the
99 Slots storing immediate values are left unchanged and the visitor does inspect
102 This is used by GC's copying, sweep and compact phases, and the implementation
103 of the become primitive.
105 Iteration is driven by visit_*() methods. Only one of them define GC roots:
108 Code block visitors iterate over sets of code blocks, applying a functor to
109 each one. The functor returns a new code_block pointer, which may or may not
110 equal the old one. This is stored back to the original location.
112 This is used by GC's sweep and compact phases, and the implementation of the
113 modify-code-heap primitive.
115 Iteration is driven by visit_*() methods. Some of them define GC roots:
116 - visit_context_code_blocks()
117 - visit_callback_code_blocks() */
119 template <typename Fixup> struct slot_visitor {
123 slot_visitor<Fixup>(factor_vm* parent, Fixup fixup)
124 : parent(parent), fixup(fixup) {}
126 cell visit_pointer(cell pointer);
127 void visit_handle(cell* handle);
128 void visit_object_array(cell* start, cell* end);
129 void visit_slots(object* ptr);
130 void visit_stack_elements(segment* region, cell* top);
131 void visit_data_roots();
132 void visit_callback_roots();
133 void visit_literal_table_roots();
134 void visit_all_roots();
135 void visit_callstack_object(callstack* stack);
136 void visit_callstack(context* ctx);
137 void visit_context(context *ctx);
138 void visit_contexts();
139 void visit_code_block_objects(code_block* compiled);
140 void visit_embedded_literals(code_block* compiled);
141 void visit_sample_callstacks();
142 void visit_sample_threads();
143 void visit_object_code_block(object* obj);
144 void visit_context_code_blocks();
145 void visit_uninitialized_code_blocks();
146 void visit_embedded_code_pointers(code_block* compiled);
147 void visit_object(object* obj);
148 void visit_mark_stack(std::vector<cell>* mark_stack);
151 template <typename Fixup>
152 cell slot_visitor<Fixup>::visit_pointer(cell pointer) {
153 if (immediate_p(pointer))
156 object* untagged = fixup.fixup_data(untag<object>(pointer));
157 return RETAG(untagged, TAG(pointer));
160 template <typename Fixup> void slot_visitor<Fixup>::visit_handle(cell* handle) {
161 *handle = visit_pointer(*handle);
164 template <typename Fixup>
165 void slot_visitor<Fixup>::visit_object_array(cell* start, cell* end) {
167 visit_handle(start++);
170 template <typename Fixup> void slot_visitor<Fixup>::visit_slots(object* obj) {
171 if (obj->type() == CALLSTACK_TYPE)
172 visit_callstack_object((callstack*)obj);
174 cell* start = (cell*)obj + 1;
175 cell* end = start + obj->slot_count(fixup);
176 visit_object_array(start, end);
180 template <typename Fixup>
181 void slot_visitor<Fixup>::visit_stack_elements(segment* region, cell* top) {
182 visit_object_array((cell*)region->start, top + 1);
185 template <typename Fixup> void slot_visitor<Fixup>::visit_data_roots() {
186 FACTOR_FOR_EACH(parent->data_roots) {
191 template <typename Fixup> void slot_visitor<Fixup>::visit_callback_roots() {
192 auto callback_slot_visitor = [&](code_block* stub, cell size) {
193 visit_handle(&stub->owner);
195 parent->callbacks->allocator->iterate(callback_slot_visitor);
198 template <typename Fixup>
199 void slot_visitor<Fixup>::visit_literal_table_roots() {
200 FACTOR_FOR_EACH(parent->code->uninitialized_blocks) {
201 iter->second = visit_pointer(iter->second);
205 template <typename Fixup> void slot_visitor<Fixup>::visit_sample_callstacks() {
206 FACTOR_FOR_EACH(parent->sample_callstacks) {
207 visit_handle(&*iter);
211 template <typename Fixup> void slot_visitor<Fixup>::visit_sample_threads() {
212 FACTOR_FOR_EACH(parent->samples) {
213 visit_handle(&iter->thread);
217 template <typename Fixup> void slot_visitor<Fixup>::visit_all_roots() {
218 visit_handle(&parent->true_object);
219 visit_handle(&parent->bignum_zero);
220 visit_handle(&parent->bignum_pos_one);
221 visit_handle(&parent->bignum_neg_one);
224 visit_callback_roots();
225 visit_literal_table_roots();
226 visit_sample_callstacks();
227 visit_sample_threads();
229 visit_object_array(parent->special_objects,
230 parent->special_objects + special_object_count);
235 /* primitive_minor_gc() is invoked by inline GC checks, and it needs to fill in
236 uninitialized stack locations before actually calling the GC. See the
237 documentation in compiler.cfg.stacks.vacant for details.
239 So for each call frame:
241 - scrub some uninitialized locations
242 - trace roots in spill slots
244 template <typename Fixup> struct call_frame_slot_visitor {
245 slot_visitor<Fixup>* visitor;
246 /* NULL in case we're a visitor for a callstack object. */
249 void scrub_stack(cell stack, uint8_t* bitmap, cell base, uint32_t count) {
250 for (cell loc = 0; loc < count; loc++) {
251 if (bitmap_p(bitmap, base + loc)) {
253 FACTOR_PRINT("scrubbing stack location " << loc);
255 *((cell*)stack - loc) = 0;
260 call_frame_slot_visitor(slot_visitor<Fixup>* visitor, context* ctx)
261 : visitor(visitor), ctx(ctx) {}
264 frame top -> [return address]
270 void operator()(cell frame_top, cell size, code_block* owner, cell addr) {
271 cell return_address = owner->offset(addr);
273 code_block* compiled =
274 Fixup::translated_code_block_map ? owner
275 : visitor->fixup.translate_code(owner);
276 gc_info* info = compiled->block_gc_info();
278 FACTOR_ASSERT(return_address < compiled->size());
279 cell callsite = info->return_address_index(return_address);
280 if (callsite == (cell)-1)
284 FACTOR_PRINT("call frame code block " << compiled << " with offset "
287 cell* stack_pointer = (cell*)frame_top;
288 uint8_t* bitmap = info->gc_info_bitmap();
291 /* Scrub vacant stack locations. */
292 scrub_stack(ctx->datastack,
294 info->callsite_scrub_d(callsite),
295 info->scrub_d_count);
296 scrub_stack(ctx->retainstack,
298 info->callsite_scrub_r(callsite),
299 info->scrub_r_count);
302 /* Subtract old value of base pointer from every derived pointer. */
303 for (cell spill_slot = 0; spill_slot < info->derived_root_count;
305 uint32_t base_pointer = info->lookup_base_pointer(callsite, spill_slot);
306 if (base_pointer != (uint32_t)-1) {
308 FACTOR_PRINT("visiting derived root " << spill_slot
309 << " with base pointer " << base_pointer);
311 stack_pointer[spill_slot] -= stack_pointer[base_pointer];
315 /* Update all GC roots, including base pointers. */
316 cell callsite_gc_roots = info->callsite_gc_roots(callsite);
318 for (cell spill_slot = 0; spill_slot < info->gc_root_count; spill_slot++) {
319 if (bitmap_p(bitmap, callsite_gc_roots + spill_slot)) {
321 FACTOR_PRINT("visiting GC root " << spill_slot);
323 visitor->visit_handle(stack_pointer + spill_slot);
327 /* Add the base pointers to obtain new derived pointer values. */
328 for (cell spill_slot = 0; spill_slot < info->derived_root_count;
330 uint32_t base_pointer = info->lookup_base_pointer(callsite, spill_slot);
331 if (base_pointer != (uint32_t)-1)
332 stack_pointer[spill_slot] += stack_pointer[base_pointer];
337 template <typename Fixup>
338 void slot_visitor<Fixup>::visit_callstack_object(callstack* stack) {
339 call_frame_slot_visitor<Fixup> call_frame_visitor(this, NULL);
340 parent->iterate_callstack_object(stack, call_frame_visitor, fixup);
343 template <typename Fixup>
344 void slot_visitor<Fixup>::visit_callstack(context* ctx) {
345 call_frame_slot_visitor<Fixup> call_frame_visitor(this, ctx);
346 parent->iterate_callstack(ctx, call_frame_visitor, fixup);
349 template <typename Fixup>
350 void slot_visitor<Fixup>::visit_context(context* ctx) {
351 /* Callstack is visited first because it scrubs the data and retain
353 visit_callstack(ctx);
355 cell ds_ptr = ctx->datastack;
356 cell rs_ptr = ctx->retainstack;
357 segment* ds_seg = ctx->datastack_seg;
358 segment* rs_seg = ctx->retainstack_seg;
359 visit_stack_elements(ds_seg, (cell*)ds_ptr);
360 visit_stack_elements(rs_seg, (cell*)rs_ptr);
361 visit_object_array(ctx->context_objects,
362 ctx->context_objects + context_object_count);
364 /* Clear out the space not visited with a known pattern. That makes
365 it easier to see if uninitialized reads are made. */
366 ctx->fill_stack_seg(ds_ptr, ds_seg, 0xbaadbadd);
367 ctx->fill_stack_seg(rs_ptr, rs_seg, 0xdaabdaab);
370 template <typename Fixup> void slot_visitor<Fixup>::visit_contexts() {
371 FACTOR_FOR_EACH(parent->active_contexts) {
372 visit_context(*iter);
376 template <typename Fixup>
377 void slot_visitor<Fixup>::visit_code_block_objects(code_block* compiled) {
378 visit_handle(&compiled->owner);
379 visit_handle(&compiled->parameters);
380 visit_handle(&compiled->relocation);
383 template <typename Fixup>
384 void slot_visitor<Fixup>::visit_embedded_literals(code_block* compiled) {
385 if (parent->code->uninitialized_p(compiled))
388 auto update_literal_refs = [&](instruction_operand op) {
389 if (op.rel_type() == RT_LITERAL)
390 op.store_value(visit_pointer(op.load_value()));
392 compiled->each_instruction_operand(update_literal_refs);
395 template <typename Fixup> struct call_frame_code_block_visitor {
398 call_frame_code_block_visitor(Fixup fixup)
401 void operator()(cell frame_top, cell size, code_block* owner, cell addr) {
402 code_block* compiled =
403 Fixup::translated_code_block_map ? owner : fixup.fixup_code(owner);
404 cell fixed_addr = compiled->address_for_offset(owner->offset(addr));
406 *(cell*)frame_top = fixed_addr;
410 template <typename Fixup>
411 void slot_visitor<Fixup>::visit_object_code_block(object* obj) {
412 switch (obj->type()) {
414 word* w = (word*)obj;
416 w->entry_point = fixup.fixup_code(w->code())->entry_point();
419 case QUOTATION_TYPE: {
420 quotation* q = (quotation*)obj;
422 q->entry_point = fixup.fixup_code(q->code())->entry_point();
425 case CALLSTACK_TYPE: {
426 callstack* stack = (callstack*)obj;
427 call_frame_code_block_visitor<Fixup> call_frame_visitor(fixup);
428 parent->iterate_callstack_object(stack, call_frame_visitor, fixup);
434 template <typename Fixup>
435 void slot_visitor<Fixup>::visit_context_code_blocks() {
436 call_frame_code_block_visitor<Fixup> call_frame_visitor(fixup);
437 FACTOR_FOR_EACH(parent->active_contexts) {
438 parent->iterate_callstack(*iter, call_frame_visitor, fixup);
442 template <typename Fixup>
443 void slot_visitor<Fixup>::visit_uninitialized_code_blocks() {
444 std::map<code_block*, cell> new_uninitialized_blocks;
445 FACTOR_FOR_EACH(parent->code->uninitialized_blocks) {
446 new_uninitialized_blocks.insert(
447 std::make_pair(fixup.fixup_code(iter->first), iter->second));
449 parent->code->uninitialized_blocks = new_uninitialized_blocks;
452 template <typename Fixup>
453 void slot_visitor<Fixup>::visit_embedded_code_pointers(code_block* compiled) {
454 if (parent->code->uninitialized_p(compiled))
456 auto update_code_block_refs = [&](instruction_operand op){
457 relocation_type type = op.rel_type();
458 if (type == RT_ENTRY_POINT ||
459 type == RT_ENTRY_POINT_PIC ||
460 type == RT_ENTRY_POINT_PIC_TAIL)
461 op.store_code_block(fixup.fixup_code(op.load_code_block()));
463 compiled->each_instruction_operand(update_code_block_refs);
466 template <typename Fixup>
467 void slot_visitor<Fixup>::visit_object(object *ptr) {
469 if (ptr->type() == ALIEN_TYPE)
470 ((alien*)ptr)->update_address();
473 /* Pops items from the mark stack and visits them until the stack is
474 empty. Used when doing a full collection and when collecting to
476 template <typename Fixup>
477 void slot_visitor<Fixup>::visit_mark_stack(std::vector<cell>* mark_stack) {
478 while (!mark_stack->empty()) {
479 cell ptr = mark_stack->back();
480 mark_stack->pop_back();
483 code_block* compiled = (code_block*)(ptr - 1);
484 visit_code_block_objects(compiled);
485 visit_embedded_literals(compiled);
486 visit_embedded_code_pointers(compiled);
488 object* obj = (object*)ptr;
490 visit_object_code_block(obj);