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_slots(object* ptr);
131 void visit_stack_elements(segment* region, cell* top);
132 void visit_all_roots();
133 void visit_callstack_object(callstack* stack);
134 void visit_callstack(context* ctx);
135 void visit_context(context *ctx);
136 void visit_code_block_objects(code_block* compiled);
137 void visit_embedded_literals(code_block* compiled);
138 void visit_object_code_block(object* obj);
139 void visit_context_code_blocks();
140 void visit_uninitialized_code_blocks();
141 void visit_embedded_code_pointers(code_block* compiled);
142 void visit_object(object* obj);
143 void visit_mark_stack(std::vector<cell>* mark_stack);
146 template <typename Fixup>
147 cell slot_visitor<Fixup>::visit_pointer(cell pointer) {
148 if (immediate_p(pointer))
151 object* untagged = fixup.fixup_data(untag<object>(pointer));
152 return RETAG(untagged, TAG(pointer));
155 template <typename Fixup> void slot_visitor<Fixup>::visit_handle(cell* handle) {
156 *handle = visit_pointer(*handle);
159 template <typename Fixup>
160 void slot_visitor<Fixup>::visit_object_array(cell* start, cell* end) {
162 visit_handle(start++);
165 template <typename Fixup> void slot_visitor<Fixup>::visit_slots(object* obj) {
166 if (obj->type() == CALLSTACK_TYPE)
167 visit_callstack_object((callstack*)obj);
169 cell* start = (cell*)obj + 1;
170 cell* end = start + obj->slot_count(fixup);
171 visit_object_array(start, end);
175 template <typename Fixup>
176 void slot_visitor<Fixup>::visit_stack_elements(segment* region, cell* top) {
177 visit_object_array((cell*)region->start, top + 1);
180 template <typename Fixup> void slot_visitor<Fixup>::visit_all_roots() {
181 visit_handle(&parent->true_object);
182 visit_handle(&parent->bignum_zero);
183 visit_handle(&parent->bignum_pos_one);
184 visit_handle(&parent->bignum_neg_one);
186 FACTOR_FOR_EACH(parent->data_roots) {
190 auto callback_slot_visitor = [&](code_block* stub, cell size) {
191 visit_handle(&stub->owner);
193 parent->callbacks->allocator->iterate(callback_slot_visitor);
195 FACTOR_FOR_EACH(parent->code->uninitialized_blocks) {
196 iter->second = visit_pointer(iter->second);
199 FACTOR_FOR_EACH(parent->sample_callstacks) {
200 visit_handle(&*iter);
203 FACTOR_FOR_EACH(parent->samples) {
204 visit_handle(&iter->thread);
207 visit_object_array(parent->special_objects,
208 parent->special_objects + special_object_count);
210 FACTOR_FOR_EACH(parent->active_contexts) {
211 visit_context(*iter);
215 /* primitive_minor_gc() is invoked by inline GC checks, and it needs to fill in
216 uninitialized stack locations before actually calling the GC. See the
217 documentation in compiler.cfg.stacks.vacant for details.
219 So for each call frame:
221 - scrub some uninitialized locations
222 - trace roots in spill slots
224 template <typename Fixup> struct call_frame_slot_visitor {
225 slot_visitor<Fixup>* visitor;
226 /* NULL in case we're a visitor for a callstack object. */
229 void scrub_stack(cell stack, uint8_t* bitmap, cell base, uint32_t count) {
230 for (cell loc = 0; loc < count; loc++) {
231 if (bitmap_p(bitmap, base + loc)) {
233 FACTOR_PRINT("scrubbing stack location " << loc);
235 *((cell*)stack - loc) = 0;
240 call_frame_slot_visitor(slot_visitor<Fixup>* visitor, context* ctx)
241 : visitor(visitor), ctx(ctx) {}
244 frame top -> [return address]
250 void operator()(cell frame_top, cell size, code_block* owner, cell addr) {
251 cell return_address = owner->offset(addr);
253 code_block* compiled =
254 Fixup::translated_code_block_map ? owner
255 : visitor->fixup.translate_code(owner);
256 gc_info* info = compiled->block_gc_info();
258 FACTOR_ASSERT(return_address < compiled->size());
259 cell callsite = info->return_address_index(return_address);
260 if (callsite == (cell)-1)
264 FACTOR_PRINT("call frame code block " << compiled << " with offset "
267 cell* stack_pointer = (cell*)frame_top;
268 uint8_t* bitmap = info->gc_info_bitmap();
271 /* Scrub vacant stack locations. */
272 scrub_stack(ctx->datastack,
274 info->callsite_scrub_d(callsite),
275 info->scrub_d_count);
276 scrub_stack(ctx->retainstack,
278 info->callsite_scrub_r(callsite),
279 info->scrub_r_count);
282 /* Subtract old value of base pointer from every derived pointer. */
283 for (cell spill_slot = 0; spill_slot < info->derived_root_count;
285 uint32_t base_pointer = info->lookup_base_pointer(callsite, spill_slot);
286 if (base_pointer != (uint32_t)-1) {
288 FACTOR_PRINT("visiting derived root " << spill_slot
289 << " with base pointer " << base_pointer);
291 stack_pointer[spill_slot] -= stack_pointer[base_pointer];
295 /* Update all GC roots, including base pointers. */
296 cell callsite_gc_roots = info->callsite_gc_roots(callsite);
298 for (cell spill_slot = 0; spill_slot < info->gc_root_count; spill_slot++) {
299 if (bitmap_p(bitmap, callsite_gc_roots + spill_slot)) {
301 FACTOR_PRINT("visiting GC root " << spill_slot);
303 visitor->visit_handle(stack_pointer + spill_slot);
307 /* Add the base pointers to obtain new derived pointer values. */
308 for (cell spill_slot = 0; spill_slot < info->derived_root_count;
310 uint32_t base_pointer = info->lookup_base_pointer(callsite, spill_slot);
311 if (base_pointer != (uint32_t)-1)
312 stack_pointer[spill_slot] += stack_pointer[base_pointer];
317 template <typename Fixup>
318 void slot_visitor<Fixup>::visit_callstack_object(callstack* stack) {
319 call_frame_slot_visitor<Fixup> call_frame_visitor(this, NULL);
320 parent->iterate_callstack_object(stack, call_frame_visitor, fixup);
323 template <typename Fixup>
324 void slot_visitor<Fixup>::visit_callstack(context* ctx) {
325 call_frame_slot_visitor<Fixup> call_frame_visitor(this, ctx);
326 parent->iterate_callstack(ctx, call_frame_visitor, fixup);
329 template <typename Fixup>
330 void slot_visitor<Fixup>::visit_context(context* ctx) {
331 /* Callstack is visited first because it scrubs the data and retain
333 visit_callstack(ctx);
335 cell ds_ptr = ctx->datastack;
336 cell rs_ptr = ctx->retainstack;
337 segment* ds_seg = ctx->datastack_seg;
338 segment* rs_seg = ctx->retainstack_seg;
339 visit_stack_elements(ds_seg, (cell*)ds_ptr);
340 visit_stack_elements(rs_seg, (cell*)rs_ptr);
341 visit_object_array(ctx->context_objects,
342 ctx->context_objects + context_object_count);
344 /* Clear out the space not visited with a known pattern. That makes
345 it easier to see if uninitialized reads are made. */
346 ctx->fill_stack_seg(ds_ptr, ds_seg, 0xbaadbadd);
347 ctx->fill_stack_seg(rs_ptr, rs_seg, 0xdaabdaab);
350 template <typename Fixup>
351 void slot_visitor<Fixup>::visit_code_block_objects(code_block* compiled) {
352 visit_handle(&compiled->owner);
353 visit_handle(&compiled->parameters);
354 visit_handle(&compiled->relocation);
357 template <typename Fixup>
358 void slot_visitor<Fixup>::visit_embedded_literals(code_block* compiled) {
359 if (parent->code->uninitialized_p(compiled))
362 auto update_literal_refs = [&](instruction_operand op) {
363 if (op.rel_type() == RT_LITERAL)
364 op.store_value(visit_pointer(op.load_value()));
366 compiled->each_instruction_operand(update_literal_refs);
369 template <typename Fixup> struct call_frame_code_block_visitor {
372 call_frame_code_block_visitor(Fixup fixup)
375 void operator()(cell frame_top, cell size, code_block* owner, cell addr) {
376 code_block* compiled =
377 Fixup::translated_code_block_map ? owner : fixup.fixup_code(owner);
378 cell fixed_addr = compiled->address_for_offset(owner->offset(addr));
380 *(cell*)frame_top = fixed_addr;
384 template <typename Fixup>
385 void slot_visitor<Fixup>::visit_object_code_block(object* obj) {
386 switch (obj->type()) {
388 word* w = (word*)obj;
390 w->entry_point = fixup.fixup_code(w->code())->entry_point();
393 case QUOTATION_TYPE: {
394 quotation* q = (quotation*)obj;
396 q->entry_point = fixup.fixup_code(q->code())->entry_point();
399 case CALLSTACK_TYPE: {
400 callstack* stack = (callstack*)obj;
401 call_frame_code_block_visitor<Fixup> call_frame_visitor(fixup);
402 parent->iterate_callstack_object(stack, call_frame_visitor, fixup);
408 template <typename Fixup>
409 void slot_visitor<Fixup>::visit_context_code_blocks() {
410 call_frame_code_block_visitor<Fixup> call_frame_visitor(fixup);
411 FACTOR_FOR_EACH(parent->active_contexts) {
412 parent->iterate_callstack(*iter, call_frame_visitor, fixup);
416 template <typename Fixup>
417 void slot_visitor<Fixup>::visit_uninitialized_code_blocks() {
418 std::map<code_block*, cell> new_uninitialized_blocks;
419 FACTOR_FOR_EACH(parent->code->uninitialized_blocks) {
420 new_uninitialized_blocks.insert(
421 std::make_pair(fixup.fixup_code(iter->first), iter->second));
423 parent->code->uninitialized_blocks = new_uninitialized_blocks;
426 template <typename Fixup>
427 void slot_visitor<Fixup>::visit_embedded_code_pointers(code_block* compiled) {
428 if (parent->code->uninitialized_p(compiled))
430 auto update_code_block_refs = [&](instruction_operand op){
431 relocation_type type = op.rel_type();
432 if (type == RT_ENTRY_POINT ||
433 type == RT_ENTRY_POINT_PIC ||
434 type == RT_ENTRY_POINT_PIC_TAIL)
435 op.store_code_block(fixup.fixup_code(op.load_code_block()));
437 compiled->each_instruction_operand(update_code_block_refs);
440 template <typename Fixup>
441 void slot_visitor<Fixup>::visit_object(object *ptr) {
443 if (ptr->type() == ALIEN_TYPE)
444 ((alien*)ptr)->update_address();
447 /* Pops items from the mark stack and visits them until the stack is
448 empty. Used when doing a full collection and when collecting to
450 template <typename Fixup>
451 void slot_visitor<Fixup>::visit_mark_stack(std::vector<cell>* mark_stack) {
452 while (!mark_stack->empty()) {
453 cell ptr = mark_stack->back();
454 mark_stack->pop_back();
457 code_block* compiled = (code_block*)(ptr - 1);
458 visit_code_block_objects(compiled);
459 visit_embedded_literals(compiled);
460 visit_embedded_code_pointers(compiled);
462 object* obj = (object*)ptr;
464 visit_object_code_block(obj);