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. Some of them define GC roots:
106 - visit_contexts() */
108 template <typename Fixup> struct slot_visitor {
112 slot_visitor<Fixup>(factor_vm* parent, Fixup fixup)
113 : parent(parent), fixup(fixup) {}
115 cell visit_pointer(cell pointer);
116 void visit_handle(cell* handle);
117 void visit_object_array(cell* start, cell* end);
118 void visit_slots(object* ptr, cell payload_start);
119 void visit_slots(object* ptr);
120 void visit_stack_elements(segment* region, cell* top);
121 void visit_data_roots();
122 void visit_bignum_roots();
123 void visit_callback_roots();
124 void visit_literal_table_roots();
126 void visit_callstack_object(callstack* stack);
127 void visit_callstack(context* ctx);
128 void visit_context(context *ctx);
129 void visit_contexts();
130 void visit_code_block_objects(code_block* compiled);
131 void visit_embedded_literals(code_block* compiled);
132 void visit_sample_callstacks();
133 void visit_sample_threads();
136 template <typename Fixup>
137 cell slot_visitor<Fixup>::visit_pointer(cell pointer) {
138 if (immediate_p(pointer))
141 object* untagged = fixup.fixup_data(untag<object>(pointer));
142 return RETAG(untagged, TAG(pointer));
145 template <typename Fixup> void slot_visitor<Fixup>::visit_handle(cell* handle) {
146 *handle = visit_pointer(*handle);
149 template <typename Fixup>
150 void slot_visitor<Fixup>::visit_object_array(cell* start, cell* end) {
152 visit_handle(start++);
155 template <typename Fixup>
156 void slot_visitor<Fixup>::visit_slots(object* ptr, cell payload_start) {
157 cell* slot = (cell*)ptr;
158 cell* end = (cell*)((cell)ptr + payload_start);
162 visit_object_array(slot, end);
166 template <typename Fixup> void slot_visitor<Fixup>::visit_slots(object* obj) {
167 if (obj->type() == CALLSTACK_TYPE)
168 visit_callstack_object((callstack*)obj);
170 visit_slots(obj, obj->binary_payload_start(fixup));
173 template <typename Fixup>
174 void slot_visitor<Fixup>::visit_stack_elements(segment* region, cell* top) {
175 visit_object_array((cell*)region->start, top + 1);
178 template <typename Fixup> void slot_visitor<Fixup>::visit_data_roots() {
179 std::vector<cell*>::const_iterator iter =
180 parent->data_roots.begin();
181 std::vector<cell*>::const_iterator end =
182 parent->data_roots.end();
184 for (; iter < end; iter++) {
189 template <typename Fixup> void slot_visitor<Fixup>::visit_bignum_roots() {
190 std::vector<bignum**>::const_iterator iter =
191 parent->bignum_roots.begin();
192 std::vector<bignum**>::const_iterator end =
193 parent->bignum_roots.end();
195 for (; iter < end; iter++) {
196 bignum** ref = *iter;
197 *ref = (bignum*)fixup.fixup_data(*ref);
201 template <typename Fixup> struct callback_slot_visitor {
202 callback_heap* callbacks;
203 slot_visitor<Fixup>* visitor;
205 callback_slot_visitor(callback_heap* callbacks,
206 slot_visitor<Fixup>* visitor)
207 : callbacks(callbacks), visitor(visitor) {}
209 void operator()(object* stub) {
210 code_block *block = (code_block*)stub;
211 visitor->visit_handle(&block->owner);
215 template <typename Fixup> void slot_visitor<Fixup>::visit_callback_roots() {
216 callback_slot_visitor<Fixup> callback_visitor(parent->callbacks, this);
217 parent->each_object(parent->callbacks->allocator, callback_visitor);
220 template <typename Fixup>
221 void slot_visitor<Fixup>::visit_literal_table_roots() {
222 std::map<code_block*, cell>* uninitialized_blocks =
223 &parent->code->uninitialized_blocks;
224 std::map<code_block*, cell>::const_iterator iter =
225 uninitialized_blocks->begin();
226 std::map<code_block*, cell>::const_iterator end = uninitialized_blocks->end();
228 std::map<code_block*, cell> new_uninitialized_blocks;
229 for (; iter != end; iter++) {
230 new_uninitialized_blocks.insert(
231 std::make_pair(iter->first, visit_pointer(iter->second)));
234 parent->code->uninitialized_blocks = new_uninitialized_blocks;
237 template <typename Fixup> void slot_visitor<Fixup>::visit_sample_callstacks() {
238 for (std::vector<cell>::iterator iter = parent->sample_callstacks.begin();
239 iter != parent->sample_callstacks.end(); ++iter) {
240 visit_handle(&*iter);
244 template <typename Fixup> void slot_visitor<Fixup>::visit_sample_threads() {
245 for (std::vector<profiling_sample>::iterator iter = parent->samples.begin();
246 iter != parent->samples.end(); ++iter) {
247 visit_handle(&iter->thread);
251 template <typename Fixup> void slot_visitor<Fixup>::visit_roots() {
252 visit_handle(&parent->true_object);
253 visit_handle(&parent->bignum_zero);
254 visit_handle(&parent->bignum_pos_one);
255 visit_handle(&parent->bignum_neg_one);
258 visit_bignum_roots();
259 visit_callback_roots();
260 visit_literal_table_roots();
261 visit_sample_callstacks();
262 visit_sample_threads();
264 visit_object_array(parent->special_objects,
265 parent->special_objects + special_object_count);
268 /* primitive_minor_gc() is invoked by inline GC checks, and it needs to fill in
269 uninitialized stack locations before actually calling the GC. See the
270 documentation in compiler.cfg.stacks.vacant for details.
272 So for each call frame:
274 - scrub some uninitialized locations
275 - trace some overinitialized locations
276 - trace roots in spill slots
278 template <typename Fixup> struct call_frame_slot_visitor {
280 slot_visitor<Fixup>* visitor;
281 /* NULL in case we're a visitor for a callstack object. */
284 void check_stack(cell stack, uint8_t* bitmap, cell base, uint32_t count) {
285 for (uint32_t loc = 0; loc < count; loc++) {
286 if (bitmap_p(bitmap, base + loc)) {
288 std::cout << "checking stack location " << loc << std::endl;
290 cell* value_ptr = ((cell*)stack + loc + 1);
291 visitor->visit_handle(value_ptr);
296 void scrub_stack(cell stack, uint8_t* bitmap, cell base, uint32_t count) {
297 for (cell loc = 0; loc < count; loc++) {
298 if (bitmap_p(bitmap, base + loc)) {
300 std::cout << "scrubbing stack location " << loc << std::endl;
302 *((cell*)stack - loc) = 0;
307 call_frame_slot_visitor(factor_vm* parent,
308 slot_visitor<Fixup>* visitor,
310 : parent(parent), visitor(visitor), ctx(ctx) {}
313 frame top -> [return address]
319 void operator()(void* frame_top, cell frame_size, code_block* owner,
321 cell return_address = owner->offset(addr);
323 code_block* compiled =
324 Fixup::translated_code_block_map ? owner
325 : visitor->fixup.translate_code(owner);
326 gc_info* info = compiled->block_gc_info();
328 FACTOR_ASSERT(return_address < compiled->size());
329 cell callsite = info->return_address_index(return_address);
330 if (callsite == (cell)-1)
334 std::cout << "call frame code block " << compiled << " with offset "
335 << return_address << std::endl;
337 cell* stack_pointer = (cell*)frame_top;
338 uint8_t* bitmap = info->gc_info_bitmap();
341 /* Scrub vacant stack locations. */
342 scrub_stack(ctx->datastack,
344 info->callsite_scrub_d(callsite),
345 info->scrub_d_count);
346 scrub_stack(ctx->retainstack,
348 info->callsite_scrub_r(callsite),
349 info->scrub_r_count);
351 /* Trace overinitialized stack locations. */
352 check_stack(ctx->datastack,
354 info->callsite_check_d(callsite),
355 info->check_d_count);
356 check_stack(ctx->retainstack,
358 info->callsite_check_r(callsite),
359 info->check_r_count);
362 /* Subtract old value of base pointer from every derived pointer. */
363 for (cell spill_slot = 0; spill_slot < info->derived_root_count;
365 uint32_t base_pointer = info->lookup_base_pointer(callsite, spill_slot);
366 if (base_pointer != (uint32_t)-1) {
368 std::cout << "visiting derived root " << spill_slot
369 << " with base pointer " << base_pointer << std::endl;
371 stack_pointer[spill_slot] -= stack_pointer[base_pointer];
375 /* Update all GC roots, including base pointers. */
376 cell callsite_gc_roots = info->callsite_gc_roots(callsite);
378 for (cell spill_slot = 0; spill_slot < info->gc_root_count; spill_slot++) {
379 if (bitmap_p(bitmap, callsite_gc_roots + spill_slot)) {
381 std::cout << "visiting GC root " << spill_slot << std::endl;
383 visitor->visit_handle(stack_pointer + spill_slot);
387 /* Add the base pointers to obtain new derived pointer values. */
388 for (cell spill_slot = 0; spill_slot < info->derived_root_count;
390 uint32_t base_pointer = info->lookup_base_pointer(callsite, spill_slot);
391 if (base_pointer != (uint32_t)-1)
392 stack_pointer[spill_slot] += stack_pointer[base_pointer];
397 template <typename Fixup>
398 void slot_visitor<Fixup>::visit_callstack_object(callstack* stack) {
399 call_frame_slot_visitor<Fixup> call_frame_visitor(parent, this, NULL);
400 parent->iterate_callstack_object(stack, call_frame_visitor, fixup);
403 template <typename Fixup>
404 void slot_visitor<Fixup>::visit_callstack(context* ctx) {
405 call_frame_slot_visitor<Fixup> call_frame_visitor(parent, this, ctx);
406 parent->iterate_callstack(ctx, call_frame_visitor, fixup);
409 template <typename Fixup>
410 void slot_visitor<Fixup>::visit_context(context* ctx) {
411 /* Callstack is visited first because it scrubs the data and retain
413 visit_callstack(ctx);
415 visit_stack_elements(ctx->datastack_seg, (cell*)ctx->datastack);
416 visit_stack_elements(ctx->retainstack_seg, (cell*)ctx->retainstack);
417 visit_object_array(ctx->context_objects,
418 ctx->context_objects + context_object_count);
422 template <typename Fixup> void slot_visitor<Fixup>::visit_contexts() {
423 std::set<context*>::const_iterator begin = parent->active_contexts.begin();
424 std::set<context*>::const_iterator end = parent->active_contexts.end();
425 while (begin != end) {
426 visit_context(*begin);
431 template <typename Fixup> struct literal_references_visitor {
432 slot_visitor<Fixup>* visitor;
434 explicit literal_references_visitor(slot_visitor<Fixup>* visitor)
435 : visitor(visitor) {}
437 void operator()(instruction_operand op) {
438 if (op.rel_type() == RT_LITERAL)
439 op.store_value(visitor->visit_pointer(op.load_value()));
443 template <typename Fixup>
444 void slot_visitor<Fixup>::visit_code_block_objects(code_block* compiled) {
445 visit_handle(&compiled->owner);
446 visit_handle(&compiled->parameters);
447 visit_handle(&compiled->relocation);
450 template <typename Fixup>
451 void slot_visitor<Fixup>::visit_embedded_literals(code_block* compiled) {
452 if (!parent->code->uninitialized_p(compiled)) {
453 literal_references_visitor<Fixup> visitor(this);
454 compiled->each_instruction_operand(visitor);