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 FACTOR_FOR_EACH(parent->data_roots) {
200 auto callback_slot_visitor = [&](code_block* stub, cell size) {
201 visit_handle(&stub->owner);
203 parent->callbacks->allocator->iterate(callback_slot_visitor);
205 FACTOR_FOR_EACH(parent->code->uninitialized_blocks) {
206 iter->second = visit_pointer(iter->second);
209 FACTOR_FOR_EACH(parent->sample_callstacks) {
210 visit_handle(&*iter);
213 FACTOR_FOR_EACH(parent->samples) {
214 visit_handle(&iter->thread);
217 visit_object_array(parent->special_objects,
218 parent->special_objects + special_object_count);
220 FACTOR_FOR_EACH(parent->active_contexts) {
221 visit_context(*iter);
225 /* primitive_minor_gc() is invoked by inline GC checks, and it needs to fill in
226 uninitialized stack locations before actually calling the GC. See the
227 documentation in compiler.cfg.stacks.vacant for details.
229 So for each call frame:
231 - scrub some uninitialized locations
232 - trace roots in spill slots
234 template <typename Fixup> struct call_frame_slot_visitor {
235 slot_visitor<Fixup>* visitor;
236 /* NULL in case we're a visitor for a callstack object. */
239 void scrub_stack(cell stack, uint8_t* bitmap, cell base, uint32_t count) {
240 for (cell loc = 0; loc < count; loc++) {
241 if (bitmap_p(bitmap, base + loc)) {
243 FACTOR_PRINT("scrubbing stack location " << loc);
245 *((cell*)stack - loc) = 0;
250 call_frame_slot_visitor(slot_visitor<Fixup>* visitor, context* ctx)
251 : visitor(visitor), ctx(ctx) {}
254 frame top -> [return address]
260 void operator()(cell frame_top, cell size, code_block* owner, cell addr) {
261 cell return_address = owner->offset(addr);
263 code_block* compiled =
264 Fixup::translated_code_block_map ? owner
265 : visitor->fixup.translate_code(owner);
266 gc_info* info = compiled->block_gc_info();
268 FACTOR_ASSERT(return_address < compiled->size());
269 cell callsite = info->return_address_index(return_address);
270 if (callsite == (cell)-1)
274 FACTOR_PRINT("call frame code block " << compiled << " with offset "
277 cell* stack_pointer = (cell*)frame_top;
278 uint8_t* bitmap = info->gc_info_bitmap();
281 /* Scrub vacant stack locations. */
282 scrub_stack(ctx->datastack,
284 info->callsite_scrub_d(callsite),
285 info->scrub_d_count);
286 scrub_stack(ctx->retainstack,
288 info->callsite_scrub_r(callsite),
289 info->scrub_r_count);
292 /* Subtract old value of base pointer from every derived pointer. */
293 for (cell spill_slot = 0; spill_slot < info->derived_root_count;
295 uint32_t base_pointer = info->lookup_base_pointer(callsite, spill_slot);
296 if (base_pointer != (uint32_t)-1) {
298 FACTOR_PRINT("visiting derived root " << spill_slot
299 << " with base pointer " << base_pointer);
301 stack_pointer[spill_slot] -= stack_pointer[base_pointer];
305 /* Update all GC roots, including base pointers. */
306 cell callsite_gc_roots = info->callsite_gc_roots(callsite);
308 for (cell spill_slot = 0; spill_slot < info->gc_root_count; spill_slot++) {
309 if (bitmap_p(bitmap, callsite_gc_roots + spill_slot)) {
311 FACTOR_PRINT("visiting GC root " << spill_slot);
313 visitor->visit_handle(stack_pointer + spill_slot);
317 /* Add the base pointers to obtain new derived pointer values. */
318 for (cell spill_slot = 0; spill_slot < info->derived_root_count;
320 uint32_t base_pointer = info->lookup_base_pointer(callsite, spill_slot);
321 if (base_pointer != (uint32_t)-1)
322 stack_pointer[spill_slot] += stack_pointer[base_pointer];
327 template <typename Fixup>
328 void slot_visitor<Fixup>::visit_callstack_object(callstack* stack) {
329 call_frame_slot_visitor<Fixup> call_frame_visitor(this, NULL);
330 parent->iterate_callstack_object(stack, call_frame_visitor, fixup);
333 template <typename Fixup>
334 void slot_visitor<Fixup>::visit_callstack(context* ctx) {
335 call_frame_slot_visitor<Fixup> call_frame_visitor(this, ctx);
336 parent->iterate_callstack(ctx, call_frame_visitor, fixup);
339 template <typename Fixup>
340 void slot_visitor<Fixup>::visit_context(context* ctx) {
341 /* Callstack is visited first because it scrubs the data and retain
343 visit_callstack(ctx);
345 cell ds_ptr = ctx->datastack;
346 cell rs_ptr = ctx->retainstack;
347 segment* ds_seg = ctx->datastack_seg;
348 segment* rs_seg = ctx->retainstack_seg;
349 visit_stack_elements(ds_seg, (cell*)ds_ptr);
350 visit_stack_elements(rs_seg, (cell*)rs_ptr);
351 visit_object_array(ctx->context_objects,
352 ctx->context_objects + context_object_count);
354 /* Clear out the space not visited with a known pattern. That makes
355 it easier to see if uninitialized reads are made. */
356 ctx->fill_stack_seg(ds_ptr, ds_seg, 0xbaadbadd);
357 ctx->fill_stack_seg(rs_ptr, rs_seg, 0xdaabdaab);
360 template <typename Fixup>
361 void slot_visitor<Fixup>::visit_code_block_objects(code_block* compiled) {
362 visit_handle(&compiled->owner);
363 visit_handle(&compiled->parameters);
364 visit_handle(&compiled->relocation);
367 template <typename Fixup>
368 void slot_visitor<Fixup>::visit_embedded_literals(code_block* compiled) {
369 if (parent->code->uninitialized_p(compiled))
372 auto update_literal_refs = [&](instruction_operand op) {
373 if (op.rel_type() == RT_LITERAL)
374 op.store_value(visit_pointer(op.load_value()));
376 compiled->each_instruction_operand(update_literal_refs);
379 template <typename Fixup> struct call_frame_code_block_visitor {
382 call_frame_code_block_visitor(Fixup fixup)
385 void operator()(cell frame_top, cell size, code_block* owner, cell addr) {
386 code_block* compiled =
387 Fixup::translated_code_block_map ? owner : fixup.fixup_code(owner);
388 cell fixed_addr = compiled->address_for_offset(owner->offset(addr));
390 *(cell*)frame_top = fixed_addr;
394 template <typename Fixup>
395 void slot_visitor<Fixup>::visit_object_code_block(object* obj) {
396 switch (obj->type()) {
398 word* w = (word*)obj;
400 w->entry_point = fixup.fixup_code(w->code())->entry_point();
403 case QUOTATION_TYPE: {
404 quotation* q = (quotation*)obj;
406 q->entry_point = fixup.fixup_code(q->code())->entry_point();
409 case CALLSTACK_TYPE: {
410 callstack* stack = (callstack*)obj;
411 call_frame_code_block_visitor<Fixup> call_frame_visitor(fixup);
412 parent->iterate_callstack_object(stack, call_frame_visitor, fixup);
418 template <typename Fixup>
419 void slot_visitor<Fixup>::visit_context_code_blocks() {
420 call_frame_code_block_visitor<Fixup> call_frame_visitor(fixup);
421 FACTOR_FOR_EACH(parent->active_contexts) {
422 parent->iterate_callstack(*iter, call_frame_visitor, fixup);
426 template <typename Fixup>
427 void slot_visitor<Fixup>::visit_uninitialized_code_blocks() {
428 std::map<code_block*, cell> new_uninitialized_blocks;
429 FACTOR_FOR_EACH(parent->code->uninitialized_blocks) {
430 new_uninitialized_blocks.insert(
431 std::make_pair(fixup.fixup_code(iter->first), iter->second));
433 parent->code->uninitialized_blocks = new_uninitialized_blocks;
436 template <typename Fixup>
437 void slot_visitor<Fixup>::visit_embedded_code_pointers(code_block* compiled) {
438 if (parent->code->uninitialized_p(compiled))
440 auto update_code_block_refs = [&](instruction_operand op){
441 relocation_type type = op.rel_type();
442 if (type == RT_ENTRY_POINT ||
443 type == RT_ENTRY_POINT_PIC ||
444 type == RT_ENTRY_POINT_PIC_TAIL)
445 op.store_code_block(fixup.fixup_code(op.load_code_block()));
447 compiled->each_instruction_operand(update_code_block_refs);
450 template <typename Fixup>
451 void slot_visitor<Fixup>::visit_object(object *ptr) {
453 if (ptr->type() == ALIEN_TYPE)
454 ((alien*)ptr)->update_address();
457 /* Pops items from the mark stack and visits them until the stack is
458 empty. Used when doing a full collection and when collecting to
460 template <typename Fixup>
461 void slot_visitor<Fixup>::visit_mark_stack(std::vector<cell>* mark_stack) {
462 while (!mark_stack->empty()) {
463 cell ptr = mark_stack->back();
464 mark_stack->pop_back();
467 code_block* compiled = (code_block*)(ptr - 1);
468 visit_code_block_objects(compiled);
469 visit_embedded_literals(compiled);
470 visit_embedded_code_pointers(compiled);
472 object* obj = (object*)ptr;
474 visit_object_code_block(obj);
479 /* Visits the instruction operands in a code block. If the operand is
480 a pointer to a code block or data object, then the fixup is applied
481 to it. Otherwise, if it is an external addess, that address is
482 recomputed. If it is an untagged number literal (RT_UNTAGGED) or an
483 immediate value, then nothing is done with it. */
484 template <typename Fixup>
485 void slot_visitor<Fixup>::visit_instruction_operands(code_block* block,
487 auto visit_func = [&](instruction_operand op){
488 cell old_offset = rel_base + op.rel_offset();
489 cell value = op.load_value(old_offset);
490 switch (op.rel_type()) {
492 value = visit_pointer(value);
496 case RT_ENTRY_POINT_PIC:
497 case RT_ENTRY_POINT_PIC_TAIL:
499 cell offset = TAG(value);
500 code_block* compiled = (code_block*)UNTAG(value);
501 value = RETAG(fixup.fixup_code(compiled), offset);
507 value = parent->compute_external_address(op);
510 op.store_value(value);
512 block->each_instruction_operand(visit_func);