3 /* Size of the object pointed to by an untagged pointer */
4 template <typename Fixup> cell object::size(Fixup fixup) const {
6 return ((free_heap_block*)this)->size();
10 return align(array_size((array*)this), data_alignment);
12 return align(array_size((bignum*)this), data_alignment);
14 return align(array_size((byte_array*)this), data_alignment);
16 return align(string_size(string_capacity((string*)this)), data_alignment);
18 tuple_layout* layout = (tuple_layout*)fixup.translate_data(
19 untag<object>(((tuple*)this)->layout));
20 return align(tuple_size(layout), data_alignment);
23 return align(sizeof(quotation), data_alignment);
25 return align(sizeof(word), data_alignment);
27 return align(sizeof(boxed_float), data_alignment);
29 return align(sizeof(dll), data_alignment);
31 return align(sizeof(alien), data_alignment);
33 return align(sizeof(wrapper), data_alignment);
36 callstack_object_size(untag_fixnum(((callstack*)this)->length)),
39 critical_error("Invalid header in size", (cell)this);
40 return 0; /* can't happen */
44 inline cell object::size() const { return size(no_fixup()); }
46 /* The number of cells from the start of the object which should be scanned by
47 the GC. Some types have a binary payload at the end (string, word, DLL) which
49 template <typename Fixup> cell object::binary_payload_start(Fixup fixup) const {
54 /* these objects do not refer to other objects at all */
60 /* these objects have some binary data at the end */
62 return sizeof(word) - sizeof(cell);
64 return sizeof(cell) * 3;
66 return sizeof(cell) * 2;
68 return sizeof(quotation) - sizeof(cell);
70 return sizeof(string);
71 /* everything else consists entirely of pointers */
73 return array_size<array>(array_capacity((array*)this));
75 tuple_layout* layout = (tuple_layout*)fixup.translate_data(
76 untag<object>(((tuple*)this)->layout));
77 return tuple_size(layout);
80 return sizeof(wrapper);
82 critical_error("Invalid header in binary_payload_start", (cell)this);
83 return 0; /* can't happen */
87 inline cell object::binary_payload_start() const {
88 return binary_payload_start(no_fixup());
91 /* Slot visitors iterate over the slots of an object, applying a functor to
92 each one that is a non-immediate slot. The pointer is untagged first. The
93 functor returns a new untagged object pointer. The return value may or may not
95 however the new pointer receives the same tag before being stored back to the
98 Slots storing immediate values are left unchanged and the visitor does inspect
101 This is used by GC's copying, sweep and compact phases, and the implementation
102 of the become primitive.
104 Iteration is driven by visit_*() methods. Only one of them define GC roots:
107 Code block visitors iterate over sets of code blocks, applying a functor to
108 each one. The functor returns a new code_block pointer, which may or may not
109 equal the old one. This is stored back to the original location.
111 This is used by GC's sweep and compact phases, and the implementation of the
112 modify-code-heap primitive.
114 Iteration is driven by visit_*() methods. Some of them define GC roots:
115 - visit_context_code_blocks()
116 - visit_callback_code_blocks() */
118 template <typename Fixup> struct slot_visitor {
122 slot_visitor<Fixup>(factor_vm* parent, Fixup fixup)
123 : parent(parent), fixup(fixup) {}
125 cell visit_pointer(cell pointer);
126 void visit_handle(cell* handle);
127 void visit_object_array(cell* start, cell* end);
128 void visit_slots(object* ptr, cell payload_start);
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>
171 void slot_visitor<Fixup>::visit_slots(object* ptr, cell payload_start) {
172 cell* slot = (cell*)ptr;
173 cell* end = (cell*)((cell)ptr + payload_start);
177 visit_object_array(slot, end);
181 template <typename Fixup> void slot_visitor<Fixup>::visit_slots(object* obj) {
182 if (obj->type() == CALLSTACK_TYPE)
183 visit_callstack_object((callstack*)obj);
185 visit_slots(obj, obj->binary_payload_start(fixup));
188 template <typename Fixup>
189 void slot_visitor<Fixup>::visit_stack_elements(segment* region, cell* top) {
190 visit_object_array((cell*)region->start, top + 1);
193 template <typename Fixup> void slot_visitor<Fixup>::visit_data_roots() {
194 FACTOR_FOR_EACH(parent->data_roots) {
199 template <typename Fixup> struct callback_slot_visitor {
200 slot_visitor<Fixup>* visitor;
202 callback_slot_visitor(slot_visitor<Fixup>* visitor) : visitor(visitor) {}
204 void operator()(code_block* stub, cell size) {
205 visitor->visit_handle(&stub->owner);
209 template <typename Fixup> void slot_visitor<Fixup>::visit_callback_roots() {
210 callback_slot_visitor<Fixup> callback_visitor(this);
211 parent->callbacks->allocator->iterate(callback_visitor);
214 template <typename Fixup>
215 void slot_visitor<Fixup>::visit_literal_table_roots() {
216 FACTOR_FOR_EACH(parent->code->uninitialized_blocks) {
217 iter->second = visit_pointer(iter->second);
221 template <typename Fixup> void slot_visitor<Fixup>::visit_sample_callstacks() {
222 FACTOR_FOR_EACH(parent->sample_callstacks) {
223 visit_handle(&*iter);
227 template <typename Fixup> void slot_visitor<Fixup>::visit_sample_threads() {
228 FACTOR_FOR_EACH(parent->samples) {
229 visit_handle(&iter->thread);
233 template <typename Fixup> void slot_visitor<Fixup>::visit_all_roots() {
234 visit_handle(&parent->true_object);
235 visit_handle(&parent->bignum_zero);
236 visit_handle(&parent->bignum_pos_one);
237 visit_handle(&parent->bignum_neg_one);
240 visit_callback_roots();
241 visit_literal_table_roots();
242 visit_sample_callstacks();
243 visit_sample_threads();
245 visit_object_array(parent->special_objects,
246 parent->special_objects + special_object_count);
251 /* primitive_minor_gc() is invoked by inline GC checks, and it needs to fill in
252 uninitialized stack locations before actually calling the GC. See the
253 documentation in compiler.cfg.stacks.vacant for details.
255 So for each call frame:
257 - scrub some uninitialized locations
258 - trace roots in spill slots
260 template <typename Fixup> struct call_frame_slot_visitor {
261 slot_visitor<Fixup>* visitor;
262 /* NULL in case we're a visitor for a callstack object. */
265 void scrub_stack(cell stack, uint8_t* bitmap, cell base, uint32_t count) {
266 for (cell loc = 0; loc < count; loc++) {
267 if (bitmap_p(bitmap, base + loc)) {
269 FACTOR_PRINT("scrubbing stack location " << loc);
271 *((cell*)stack - loc) = 0;
276 call_frame_slot_visitor(slot_visitor<Fixup>* visitor, context* ctx)
277 : visitor(visitor), ctx(ctx) {}
280 frame top -> [return address]
286 void operator()(cell frame_top, cell size, code_block* owner, cell addr) {
287 cell return_address = owner->offset(addr);
289 code_block* compiled =
290 Fixup::translated_code_block_map ? owner
291 : visitor->fixup.translate_code(owner);
292 gc_info* info = compiled->block_gc_info();
294 FACTOR_ASSERT(return_address < compiled->size());
295 cell callsite = info->return_address_index(return_address);
296 if (callsite == (cell)-1)
300 FACTOR_PRINT("call frame code block " << compiled << " with offset "
303 cell* stack_pointer = (cell*)frame_top;
304 uint8_t* bitmap = info->gc_info_bitmap();
307 /* Scrub vacant stack locations. */
308 scrub_stack(ctx->datastack,
310 info->callsite_scrub_d(callsite),
311 info->scrub_d_count);
312 scrub_stack(ctx->retainstack,
314 info->callsite_scrub_r(callsite),
315 info->scrub_r_count);
318 /* Subtract old value of base pointer from every derived pointer. */
319 for (cell spill_slot = 0; spill_slot < info->derived_root_count;
321 uint32_t base_pointer = info->lookup_base_pointer(callsite, spill_slot);
322 if (base_pointer != (uint32_t)-1) {
324 FACTOR_PRINT("visiting derived root " << spill_slot
325 << " with base pointer " << base_pointer);
327 stack_pointer[spill_slot] -= stack_pointer[base_pointer];
331 /* Update all GC roots, including base pointers. */
332 cell callsite_gc_roots = info->callsite_gc_roots(callsite);
334 for (cell spill_slot = 0; spill_slot < info->gc_root_count; spill_slot++) {
335 if (bitmap_p(bitmap, callsite_gc_roots + spill_slot)) {
337 FACTOR_PRINT("visiting GC root " << spill_slot);
339 visitor->visit_handle(stack_pointer + spill_slot);
343 /* Add the base pointers to obtain new derived pointer values. */
344 for (cell spill_slot = 0; spill_slot < info->derived_root_count;
346 uint32_t base_pointer = info->lookup_base_pointer(callsite, spill_slot);
347 if (base_pointer != (uint32_t)-1)
348 stack_pointer[spill_slot] += stack_pointer[base_pointer];
353 template <typename Fixup>
354 void slot_visitor<Fixup>::visit_callstack_object(callstack* stack) {
355 call_frame_slot_visitor<Fixup> call_frame_visitor(this, NULL);
356 parent->iterate_callstack_object(stack, call_frame_visitor, fixup);
359 template <typename Fixup>
360 void slot_visitor<Fixup>::visit_callstack(context* ctx) {
361 call_frame_slot_visitor<Fixup> call_frame_visitor(this, ctx);
362 parent->iterate_callstack(ctx, call_frame_visitor, fixup);
365 template <typename Fixup>
366 void slot_visitor<Fixup>::visit_context(context* ctx) {
367 /* Callstack is visited first because it scrubs the data and retain
369 visit_callstack(ctx);
371 cell ds_ptr = ctx->datastack;
372 cell rs_ptr = ctx->retainstack;
373 segment* ds_seg = ctx->datastack_seg;
374 segment* rs_seg = ctx->retainstack_seg;
375 visit_stack_elements(ds_seg, (cell*)ds_ptr);
376 visit_stack_elements(rs_seg, (cell*)rs_ptr);
377 visit_object_array(ctx->context_objects,
378 ctx->context_objects + context_object_count);
380 /* Clear out the space not visited with a known pattern. That makes
381 it easier to see if uninitialized reads are made. */
382 ctx->fill_stack_seg(ds_ptr, ds_seg, 0xbaadbadd);
383 ctx->fill_stack_seg(rs_ptr, rs_seg, 0xdaabdaab);
386 template <typename Fixup> void slot_visitor<Fixup>::visit_contexts() {
387 FACTOR_FOR_EACH(parent->active_contexts) {
388 visit_context(*iter);
392 template <typename Fixup> struct literal_references_visitor {
393 slot_visitor<Fixup>* visitor;
395 explicit literal_references_visitor(slot_visitor<Fixup>* visitor)
396 : visitor(visitor) {}
398 void operator()(instruction_operand op) {
399 if (op.rel_type() == RT_LITERAL)
400 op.store_value(visitor->visit_pointer(op.load_value()));
404 template <typename Fixup>
405 void slot_visitor<Fixup>::visit_code_block_objects(code_block* compiled) {
406 visit_handle(&compiled->owner);
407 visit_handle(&compiled->parameters);
408 visit_handle(&compiled->relocation);
411 template <typename Fixup>
412 void slot_visitor<Fixup>::visit_embedded_literals(code_block* compiled) {
413 if (!parent->code->uninitialized_p(compiled)) {
414 literal_references_visitor<Fixup> visitor(this);
415 compiled->each_instruction_operand(visitor);
419 template <typename Fixup> struct call_frame_code_block_visitor {
422 call_frame_code_block_visitor(Fixup fixup)
425 void operator()(cell frame_top, cell size, code_block* owner, cell addr) {
426 code_block* compiled =
427 Fixup::translated_code_block_map ? owner : fixup.fixup_code(owner);
428 cell fixed_addr = compiled->address_for_offset(owner->offset(addr));
430 *(cell*)frame_top = fixed_addr;
434 template <typename Fixup>
435 void slot_visitor<Fixup>::visit_object_code_block(object* obj) {
436 switch (obj->type()) {
438 word* w = (word*)obj;
440 w->entry_point = fixup.fixup_code(w->code())->entry_point();
443 case QUOTATION_TYPE: {
444 quotation* q = (quotation*)obj;
446 q->entry_point = fixup.fixup_code(q->code())->entry_point();
449 case CALLSTACK_TYPE: {
450 callstack* stack = (callstack*)obj;
451 call_frame_code_block_visitor<Fixup> call_frame_visitor(fixup);
452 parent->iterate_callstack_object(stack, call_frame_visitor, fixup);
458 template <typename Fixup>
459 void slot_visitor<Fixup>::visit_context_code_blocks() {
460 call_frame_code_block_visitor<Fixup> call_frame_visitor(fixup);
461 FACTOR_FOR_EACH(parent->active_contexts) {
462 parent->iterate_callstack(*iter, call_frame_visitor, fixup);
466 template <typename Fixup>
467 void slot_visitor<Fixup>::visit_uninitialized_code_blocks() {
468 std::map<code_block*, cell> new_uninitialized_blocks;
469 FACTOR_FOR_EACH(parent->code->uninitialized_blocks) {
470 new_uninitialized_blocks.insert(
471 std::make_pair(fixup.fixup_code(iter->first), iter->second));
473 parent->code->uninitialized_blocks = new_uninitialized_blocks;
476 template <typename Fixup> struct embedded_code_pointers_visitor {
479 explicit embedded_code_pointers_visitor(Fixup fixup) : fixup(fixup) {}
481 void operator()(instruction_operand op) {
482 relocation_type type = op.rel_type();
483 if (type == RT_ENTRY_POINT || type == RT_ENTRY_POINT_PIC ||
484 type == RT_ENTRY_POINT_PIC_TAIL)
485 op.store_code_block(fixup.fixup_code(op.load_code_block()));
489 template <typename Fixup>
490 void slot_visitor<Fixup>::visit_embedded_code_pointers(code_block* compiled) {
491 if (!parent->code->uninitialized_p(compiled)) {
492 embedded_code_pointers_visitor<Fixup> operand_visitor(fixup);
493 compiled->each_instruction_operand(operand_visitor);
497 template <typename Fixup>
498 void slot_visitor<Fixup>::visit_object(object *ptr) {
500 if (ptr->type() == ALIEN_TYPE)
501 ((alien*)ptr)->update_address();
504 /* Pops items from the mark stack and visits them until the stack is
505 empty. Used when doing a full collection and when collecting to
507 template <typename Fixup>
508 void slot_visitor<Fixup>::visit_mark_stack(std::vector<cell>* mark_stack) {
509 while (!mark_stack->empty()) {
510 cell ptr = mark_stack->back();
512 mark_stack->pop_back();
515 code_block* compiled = (code_block*)(ptr - 1);
516 visit_code_block_objects(compiled);
517 visit_embedded_literals(compiled);
518 visit_embedded_code_pointers(compiled);
520 object* obj = (object*)ptr;
522 visit_object_code_block(obj);