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 slot_visitor<Fixup>* visitor;
204 callback_slot_visitor(slot_visitor<Fixup>* visitor) : visitor(visitor) {}
206 void operator()(code_block* stub, cell size) {
207 visitor->visit_handle(&stub->owner);
211 template <typename Fixup> void slot_visitor<Fixup>::visit_callback_roots() {
212 callback_slot_visitor<Fixup> callback_visitor(this);
213 parent->callbacks->allocator->iterate(callback_visitor);
216 template <typename Fixup>
217 void slot_visitor<Fixup>::visit_literal_table_roots() {
218 std::map<code_block*, cell>* uninitialized_blocks =
219 &parent->code->uninitialized_blocks;
220 std::map<code_block*, cell>::const_iterator iter =
221 uninitialized_blocks->begin();
222 std::map<code_block*, cell>::const_iterator end = uninitialized_blocks->end();
224 std::map<code_block*, cell> new_uninitialized_blocks;
225 for (; iter != end; iter++) {
226 new_uninitialized_blocks.insert(
227 std::make_pair(iter->first, visit_pointer(iter->second)));
230 parent->code->uninitialized_blocks = new_uninitialized_blocks;
233 template <typename Fixup> void slot_visitor<Fixup>::visit_sample_callstacks() {
234 for (std::vector<cell>::iterator iter = parent->sample_callstacks.begin();
235 iter != parent->sample_callstacks.end(); ++iter) {
236 visit_handle(&*iter);
240 template <typename Fixup> void slot_visitor<Fixup>::visit_sample_threads() {
241 for (std::vector<profiling_sample>::iterator iter = parent->samples.begin();
242 iter != parent->samples.end(); ++iter) {
243 visit_handle(&iter->thread);
247 template <typename Fixup> void slot_visitor<Fixup>::visit_roots() {
248 visit_handle(&parent->true_object);
249 visit_handle(&parent->bignum_zero);
250 visit_handle(&parent->bignum_pos_one);
251 visit_handle(&parent->bignum_neg_one);
254 visit_bignum_roots();
255 visit_callback_roots();
256 visit_literal_table_roots();
257 visit_sample_callstacks();
258 visit_sample_threads();
260 visit_object_array(parent->special_objects,
261 parent->special_objects + special_object_count);
264 /* primitive_minor_gc() is invoked by inline GC checks, and it needs to fill in
265 uninitialized stack locations before actually calling the GC. See the
266 documentation in compiler.cfg.stacks.vacant for details.
268 So for each call frame:
270 - scrub some uninitialized locations
271 - trace some overinitialized locations
272 - trace roots in spill slots
274 template <typename Fixup> struct call_frame_slot_visitor {
276 slot_visitor<Fixup>* visitor;
277 /* NULL in case we're a visitor for a callstack object. */
280 void check_stack(cell stack, uint8_t* bitmap, cell base, uint32_t count) {
281 for (uint32_t loc = 0; loc < count; loc++) {
282 if (bitmap_p(bitmap, base + loc)) {
284 std::cout << "checking stack location " << loc << std::endl;
286 cell* value_ptr = ((cell*)stack + loc + 1);
287 visitor->visit_handle(value_ptr);
292 void scrub_stack(cell stack, uint8_t* bitmap, cell base, uint32_t count) {
293 for (cell loc = 0; loc < count; loc++) {
294 if (bitmap_p(bitmap, base + loc)) {
296 std::cout << "scrubbing stack location " << loc << std::endl;
298 *((cell*)stack - loc) = 0;
303 call_frame_slot_visitor(factor_vm* parent,
304 slot_visitor<Fixup>* visitor,
306 : parent(parent), visitor(visitor), ctx(ctx) {}
309 frame top -> [return address]
315 void operator()(void* frame_top, cell frame_size, code_block* owner,
317 cell return_address = owner->offset(addr);
319 code_block* compiled =
320 Fixup::translated_code_block_map ? owner
321 : visitor->fixup.translate_code(owner);
322 gc_info* info = compiled->block_gc_info();
324 FACTOR_ASSERT(return_address < compiled->size());
325 cell callsite = info->return_address_index(return_address);
326 if (callsite == (cell)-1)
330 std::cout << "call frame code block " << compiled << " with offset "
331 << return_address << std::endl;
333 cell* stack_pointer = (cell*)frame_top;
334 uint8_t* bitmap = info->gc_info_bitmap();
337 /* Scrub vacant stack locations. */
338 scrub_stack(ctx->datastack,
340 info->callsite_scrub_d(callsite),
341 info->scrub_d_count);
342 scrub_stack(ctx->retainstack,
344 info->callsite_scrub_r(callsite),
345 info->scrub_r_count);
347 /* Trace overinitialized stack locations. */
348 check_stack(ctx->datastack,
350 info->callsite_check_d(callsite),
351 info->check_d_count);
352 check_stack(ctx->retainstack,
354 info->callsite_check_r(callsite),
355 info->check_r_count);
358 /* Subtract old value of base pointer from every derived pointer. */
359 for (cell spill_slot = 0; spill_slot < info->derived_root_count;
361 uint32_t base_pointer = info->lookup_base_pointer(callsite, spill_slot);
362 if (base_pointer != (uint32_t)-1) {
364 std::cout << "visiting derived root " << spill_slot
365 << " with base pointer " << base_pointer << std::endl;
367 stack_pointer[spill_slot] -= stack_pointer[base_pointer];
371 /* Update all GC roots, including base pointers. */
372 cell callsite_gc_roots = info->callsite_gc_roots(callsite);
374 for (cell spill_slot = 0; spill_slot < info->gc_root_count; spill_slot++) {
375 if (bitmap_p(bitmap, callsite_gc_roots + spill_slot)) {
377 std::cout << "visiting GC root " << spill_slot << std::endl;
379 visitor->visit_handle(stack_pointer + spill_slot);
383 /* Add the base pointers to obtain new derived pointer values. */
384 for (cell spill_slot = 0; spill_slot < info->derived_root_count;
386 uint32_t base_pointer = info->lookup_base_pointer(callsite, spill_slot);
387 if (base_pointer != (uint32_t)-1)
388 stack_pointer[spill_slot] += stack_pointer[base_pointer];
393 template <typename Fixup>
394 void slot_visitor<Fixup>::visit_callstack_object(callstack* stack) {
395 call_frame_slot_visitor<Fixup> call_frame_visitor(parent, this, NULL);
396 parent->iterate_callstack_object(stack, call_frame_visitor, fixup);
399 template <typename Fixup>
400 void slot_visitor<Fixup>::visit_callstack(context* ctx) {
401 call_frame_slot_visitor<Fixup> call_frame_visitor(parent, this, ctx);
402 parent->iterate_callstack(ctx, call_frame_visitor, fixup);
405 template <typename Fixup>
406 void slot_visitor<Fixup>::visit_context(context* ctx) {
407 /* Callstack is visited first because it scrubs the data and retain
409 visit_callstack(ctx);
411 visit_stack_elements(ctx->datastack_seg, (cell*)ctx->datastack);
412 visit_stack_elements(ctx->retainstack_seg, (cell*)ctx->retainstack);
413 visit_object_array(ctx->context_objects,
414 ctx->context_objects + context_object_count);
418 template <typename Fixup> void slot_visitor<Fixup>::visit_contexts() {
419 std::set<context*>::const_iterator begin = parent->active_contexts.begin();
420 std::set<context*>::const_iterator end = parent->active_contexts.end();
421 while (begin != end) {
422 visit_context(*begin);
427 template <typename Fixup> struct literal_references_visitor {
428 slot_visitor<Fixup>* visitor;
430 explicit literal_references_visitor(slot_visitor<Fixup>* visitor)
431 : visitor(visitor) {}
433 void operator()(instruction_operand op) {
434 if (op.rel_type() == RT_LITERAL)
435 op.store_value(visitor->visit_pointer(op.load_value()));
439 template <typename Fixup>
440 void slot_visitor<Fixup>::visit_code_block_objects(code_block* compiled) {
441 visit_handle(&compiled->owner);
442 visit_handle(&compiled->parameters);
443 visit_handle(&compiled->relocation);
446 template <typename Fixup>
447 void slot_visitor<Fixup>::visit_embedded_literals(code_block* compiled) {
448 if (!parent->code->uninitialized_p(compiled)) {
449 literal_references_visitor<Fixup> visitor(this);
450 compiled->each_instruction_operand(visitor);