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 cell callstack_length = untag_fixnum(((callstack*)this)->length);
34 return callstack_object_size(callstack_length);
37 critical_error("Invalid header in base_size", (cell)this);
42 /* Size of the object pointed to by an untagged pointer */
43 template <typename Fixup>
44 cell object::size(Fixup fixup) const {
46 return ((free_heap_block*)this)->size();
47 return align(base_size(fixup), data_alignment);
50 inline cell object::size() const { return size(no_fixup()); }
52 /* The number of slots (cells) in an object which should be scanned by
53 the GC. The number can vary in arrays and tuples, in all other
54 types the number is a constant. */
55 template <typename Fixup>
56 inline cell object::slot_count(Fixup fixup) const {
61 if (t == ARRAY_TYPE) {
62 /* capacity + n slots */
63 return 1 + array_capacity((array*)this);
64 } else if (t == TUPLE_TYPE) {
65 tuple_layout* layout = (tuple_layout*)fixup.translate_data(
66 untag<object>(((tuple*)this)->layout));
67 /* layout + n slots */
68 return 1 + tuple_capacity(layout);
71 /* these objects do not refer to other objects at all */
75 case CALLSTACK_TYPE: return 0;
76 case WORD_TYPE: return 8;
77 case ALIEN_TYPE: return 2;
78 case DLL_TYPE: return 1;
79 case QUOTATION_TYPE: return 3;
80 case STRING_TYPE: return 3;
81 case WRAPPER_TYPE: return 1;
83 critical_error("Invalid header in slot_count", (cell)this);
84 return 0; /* can't happen */
89 inline cell object::slot_count() const {
90 return slot_count(no_fixup());
93 /* Slot visitors iterate over the slots of an object, applying a functor to
94 each one that is a non-immediate slot. The pointer is untagged first. The
95 functor returns a new untagged object pointer. The return value may or may not
97 however the new pointer receives the same tag before being stored back to the
100 Slots storing immediate values are left unchanged and the visitor does inspect
103 This is used by GC's copying, sweep and compact phases, and the implementation
104 of the become primitive.
106 Iteration is driven by visit_*() methods. Only one of them define GC roots:
109 Code block visitors iterate over sets of code blocks, applying a functor to
110 each one. The functor returns a new code_block pointer, which may or may not
111 equal the old one. This is stored back to the original location.
113 This is used by GC's sweep and compact phases, and the implementation of the
114 modify-code-heap primitive.
116 Iteration is driven by visit_*() methods. Some of them define GC roots:
117 - visit_context_code_blocks()
118 - visit_callback_code_blocks() */
120 template <typename Fixup> struct slot_visitor {
124 slot_visitor<Fixup>(factor_vm* parent, Fixup fixup)
125 : parent(parent), fixup(fixup) {}
127 cell visit_pointer(cell pointer);
128 void visit_handle(cell* handle);
129 void visit_object_array(cell* start, cell* end);
130 void visit_partial_objects(cell start, cell card_start, cell card_end);
131 void visit_slots(object* ptr);
132 void visit_stack_elements(segment* region, cell* top);
133 void visit_all_roots();
134 void visit_callstack_object(callstack* stack);
135 void visit_callstack(context* ctx);
136 void visit_context(context *ctx);
137 void visit_code_block_objects(code_block* compiled);
138 void visit_embedded_literals(code_block* compiled);
139 void visit_object_code_block(object* obj);
140 void visit_context_code_blocks();
141 void visit_uninitialized_code_blocks();
142 void visit_embedded_code_pointers(code_block* compiled);
143 void visit_object(object* obj);
144 void visit_mark_stack(std::vector<cell>* mark_stack);
145 void visit_instruction_operands(code_block* block, cell rel_base);
148 template <typename Fixup>
149 cell slot_visitor<Fixup>::visit_pointer(cell pointer) {
150 if (immediate_p(pointer))
153 object* untagged = fixup.fixup_data(untag<object>(pointer));
154 return RETAG(untagged, TAG(pointer));
157 template <typename Fixup> void slot_visitor<Fixup>::visit_handle(cell* handle) {
158 *handle = visit_pointer(*handle);
161 template <typename Fixup>
162 void slot_visitor<Fixup>::visit_object_array(cell* start, cell* end) {
164 visit_handle(start++);
167 template <typename Fixup>
168 void slot_visitor<Fixup>::visit_partial_objects(cell start,
171 cell *scan_start = (cell*)start + 1;
172 cell *scan_end = scan_start + ((object*)start)->slot_count();
174 scan_start = std::max(scan_start, (cell*)card_start);
175 scan_end = std::min(scan_end, (cell*)card_end);
177 visit_object_array(scan_start, scan_end);
180 template <typename Fixup> void slot_visitor<Fixup>::visit_slots(object* obj) {
181 if (obj->type() == CALLSTACK_TYPE)
182 visit_callstack_object((callstack*)obj);
184 cell* start = (cell*)obj + 1;
185 cell* end = start + obj->slot_count(fixup);
186 visit_object_array(start, end);
190 template <typename Fixup>
191 void slot_visitor<Fixup>::visit_stack_elements(segment* region, cell* top) {
192 visit_object_array((cell*)region->start, top + 1);
195 template <typename Fixup> void slot_visitor<Fixup>::visit_all_roots() {
196 visit_handle(&parent->true_object);
197 visit_handle(&parent->bignum_zero);
198 visit_handle(&parent->bignum_pos_one);
199 visit_handle(&parent->bignum_neg_one);
201 FACTOR_FOR_EACH(parent->data_roots) {
205 auto callback_slot_visitor = [&](code_block* stub, cell size) {
206 visit_handle(&stub->owner);
208 parent->callbacks->allocator->iterate(callback_slot_visitor);
210 FACTOR_FOR_EACH(parent->code->uninitialized_blocks) {
211 iter->second = visit_pointer(iter->second);
214 FACTOR_FOR_EACH(parent->sample_callstacks) {
215 visit_handle(&*iter);
218 FACTOR_FOR_EACH(parent->samples) {
219 visit_handle(&iter->thread);
222 visit_object_array(parent->special_objects,
223 parent->special_objects + special_object_count);
225 FACTOR_FOR_EACH(parent->active_contexts) {
226 visit_context(*iter);
230 /* primitive_minor_gc() is invoked by inline GC checks, and it needs to fill in
231 uninitialized stack locations before actually calling the GC. See the
232 documentation in compiler.cfg.stacks.vacant for details.
234 So for each call frame:
236 - scrub some uninitialized locations
237 - trace roots in spill slots
239 template <typename Fixup> struct call_frame_slot_visitor {
240 slot_visitor<Fixup>* visitor;
241 /* NULL in case we're a visitor for a callstack object. */
244 void scrub_stack(cell stack, uint8_t* bitmap, cell base, uint32_t count) {
245 for (cell loc = 0; loc < count; loc++) {
246 if (bitmap_p(bitmap, base + loc)) {
248 FACTOR_PRINT("scrubbing stack location " << loc);
250 *((cell*)stack - loc) = 0;
255 call_frame_slot_visitor(slot_visitor<Fixup>* visitor, context* ctx)
256 : visitor(visitor), ctx(ctx) {}
259 frame top -> [return address]
265 void operator()(cell frame_top, cell size, code_block* owner, cell addr) {
266 cell return_address = owner->offset(addr);
268 code_block* compiled =
269 Fixup::translated_code_block_map ? owner
270 : visitor->fixup.translate_code(owner);
271 gc_info* info = compiled->block_gc_info();
273 FACTOR_ASSERT(return_address < compiled->size());
274 cell callsite = info->return_address_index(return_address);
275 if (callsite == (cell)-1)
279 FACTOR_PRINT("call frame code block " << compiled << " with offset "
282 cell* stack_pointer = (cell*)frame_top;
283 uint8_t* bitmap = info->gc_info_bitmap();
286 /* Scrub vacant stack locations. */
287 scrub_stack(ctx->datastack,
289 info->callsite_scrub_d(callsite),
290 info->scrub_d_count);
291 scrub_stack(ctx->retainstack,
293 info->callsite_scrub_r(callsite),
294 info->scrub_r_count);
297 /* Subtract old value of base pointer from every derived pointer. */
298 for (cell spill_slot = 0; spill_slot < info->derived_root_count;
300 uint32_t base_pointer = info->lookup_base_pointer(callsite, spill_slot);
301 if (base_pointer != (uint32_t)-1) {
303 FACTOR_PRINT("visiting derived root " << spill_slot
304 << " with base pointer " << base_pointer);
306 stack_pointer[spill_slot] -= stack_pointer[base_pointer];
310 /* Update all GC roots, including base pointers. */
311 cell callsite_gc_roots = info->callsite_gc_roots(callsite);
313 for (cell spill_slot = 0; spill_slot < info->gc_root_count; spill_slot++) {
314 if (bitmap_p(bitmap, callsite_gc_roots + spill_slot)) {
316 FACTOR_PRINT("visiting GC root " << spill_slot);
318 visitor->visit_handle(stack_pointer + spill_slot);
322 /* Add the base pointers to obtain new derived pointer values. */
323 for (cell spill_slot = 0; spill_slot < info->derived_root_count;
325 uint32_t base_pointer = info->lookup_base_pointer(callsite, spill_slot);
326 if (base_pointer != (uint32_t)-1)
327 stack_pointer[spill_slot] += stack_pointer[base_pointer];
332 template <typename Fixup>
333 void slot_visitor<Fixup>::visit_callstack_object(callstack* stack) {
334 call_frame_slot_visitor<Fixup> call_frame_visitor(this, NULL);
335 parent->iterate_callstack_object(stack, call_frame_visitor, fixup);
338 template <typename Fixup>
339 void slot_visitor<Fixup>::visit_callstack(context* ctx) {
340 call_frame_slot_visitor<Fixup> call_frame_visitor(this, ctx);
341 parent->iterate_callstack(ctx, call_frame_visitor, fixup);
344 template <typename Fixup>
345 void slot_visitor<Fixup>::visit_context(context* ctx) {
346 /* Callstack is visited first because it scrubs the data and retain
348 visit_callstack(ctx);
350 cell ds_ptr = ctx->datastack;
351 cell rs_ptr = ctx->retainstack;
352 segment* ds_seg = ctx->datastack_seg;
353 segment* rs_seg = ctx->retainstack_seg;
354 visit_stack_elements(ds_seg, (cell*)ds_ptr);
355 visit_stack_elements(rs_seg, (cell*)rs_ptr);
356 visit_object_array(ctx->context_objects,
357 ctx->context_objects + context_object_count);
359 /* Clear out the space not visited with a known pattern. That makes
360 it easier to see if uninitialized reads are made. */
361 ctx->fill_stack_seg(ds_ptr, ds_seg, 0xbaadbadd);
362 ctx->fill_stack_seg(rs_ptr, rs_seg, 0xdaabdaab);
365 template <typename Fixup>
366 void slot_visitor<Fixup>::visit_code_block_objects(code_block* compiled) {
367 visit_handle(&compiled->owner);
368 visit_handle(&compiled->parameters);
369 visit_handle(&compiled->relocation);
372 template <typename Fixup>
373 void slot_visitor<Fixup>::visit_embedded_literals(code_block* compiled) {
374 if (parent->code->uninitialized_p(compiled))
377 auto update_literal_refs = [&](instruction_operand op) {
378 if (op.rel_type() == RT_LITERAL)
379 op.store_value(visit_pointer(op.load_value()));
381 compiled->each_instruction_operand(update_literal_refs);
384 template <typename Fixup> struct call_frame_code_block_visitor {
387 call_frame_code_block_visitor(Fixup fixup)
390 void operator()(cell frame_top, cell size, code_block* owner, cell addr) {
391 code_block* compiled =
392 Fixup::translated_code_block_map ? owner : fixup.fixup_code(owner);
393 cell fixed_addr = compiled->address_for_offset(owner->offset(addr));
395 *(cell*)frame_top = fixed_addr;
399 template <typename Fixup>
400 void slot_visitor<Fixup>::visit_object_code_block(object* obj) {
401 switch (obj->type()) {
403 word* w = (word*)obj;
405 w->entry_point = fixup.fixup_code(w->code())->entry_point();
408 case QUOTATION_TYPE: {
409 quotation* q = (quotation*)obj;
411 q->entry_point = fixup.fixup_code(q->code())->entry_point();
414 case CALLSTACK_TYPE: {
415 callstack* stack = (callstack*)obj;
416 call_frame_code_block_visitor<Fixup> call_frame_visitor(fixup);
417 parent->iterate_callstack_object(stack, call_frame_visitor, fixup);
423 template <typename Fixup>
424 void slot_visitor<Fixup>::visit_context_code_blocks() {
425 call_frame_code_block_visitor<Fixup> call_frame_visitor(fixup);
426 FACTOR_FOR_EACH(parent->active_contexts) {
427 parent->iterate_callstack(*iter, call_frame_visitor, fixup);
431 template <typename Fixup>
432 void slot_visitor<Fixup>::visit_uninitialized_code_blocks() {
433 std::map<code_block*, cell> new_uninitialized_blocks;
434 FACTOR_FOR_EACH(parent->code->uninitialized_blocks) {
435 new_uninitialized_blocks.insert(
436 std::make_pair(fixup.fixup_code(iter->first), iter->second));
438 parent->code->uninitialized_blocks = new_uninitialized_blocks;
441 template <typename Fixup>
442 void slot_visitor<Fixup>::visit_embedded_code_pointers(code_block* compiled) {
443 if (parent->code->uninitialized_p(compiled))
445 auto update_code_block_refs = [&](instruction_operand op){
446 relocation_type type = op.rel_type();
447 if (type == RT_ENTRY_POINT ||
448 type == RT_ENTRY_POINT_PIC ||
449 type == RT_ENTRY_POINT_PIC_TAIL)
450 op.store_code_block(fixup.fixup_code(op.load_code_block()));
452 compiled->each_instruction_operand(update_code_block_refs);
455 template <typename Fixup>
456 void slot_visitor<Fixup>::visit_object(object *ptr) {
458 if (ptr->type() == ALIEN_TYPE)
459 ((alien*)ptr)->update_address();
462 /* Pops items from the mark stack and visits them until the stack is
463 empty. Used when doing a full collection and when collecting to
465 template <typename Fixup>
466 void slot_visitor<Fixup>::visit_mark_stack(std::vector<cell>* mark_stack) {
467 while (!mark_stack->empty()) {
468 cell ptr = mark_stack->back();
469 mark_stack->pop_back();
472 code_block* compiled = (code_block*)(ptr - 1);
473 visit_code_block_objects(compiled);
474 visit_embedded_literals(compiled);
475 visit_embedded_code_pointers(compiled);
477 object* obj = (object*)ptr;
479 visit_object_code_block(obj);
484 /* Visits the instruction operands in a code block. If the operand is
485 a pointer to a code block or data object, then the fixup is applied
486 to it. Otherwise, if it is an external addess, that address is
487 recomputed. If it is an untagged number literal (RT_UNTAGGED) or an
488 immediate value, then nothing is done with it. */
489 template <typename Fixup>
490 void slot_visitor<Fixup>::visit_instruction_operands(code_block* block,
492 auto visit_func = [&](instruction_operand op){
493 cell old_offset = rel_base + op.rel_offset();
494 cell value = op.load_value(old_offset);
495 switch (op.rel_type()) {
497 value = visit_pointer(value);
501 case RT_ENTRY_POINT_PIC:
502 case RT_ENTRY_POINT_PIC_TAIL:
504 cell offset = TAG(value);
505 code_block* compiled = (code_block*)UNTAG(value);
506 value = RETAG(fixup.fixup_code(compiled), offset);
512 value = parent->compute_external_address(op);
515 op.store_value(value);
517 block->each_instruction_operand(visit_func);