4 /* Size of the object pointed to by an untagged pointer */
5 template<typename Fixup>
6 cell object::size(Fixup fixup) const
8 if(free_p()) return ((free_heap_block *)this)->size();
13 return align(array_size((array*)this),data_alignment);
15 return align(array_size((bignum*)this),data_alignment);
17 return align(array_size((byte_array*)this),data_alignment);
19 return align(string_size(string_capacity((string*)this)),data_alignment);
22 tuple_layout *layout = (tuple_layout *)fixup.translate_data(untag<object>(((tuple *)this)->layout));
23 return align(tuple_size(layout),data_alignment);
26 return align(sizeof(quotation),data_alignment);
28 return align(sizeof(word),data_alignment);
30 return align(sizeof(boxed_float),data_alignment);
32 return align(sizeof(dll),data_alignment);
34 return align(sizeof(alien),data_alignment);
36 return align(sizeof(wrapper),data_alignment);
38 return align(callstack_object_size(untag_fixnum(((callstack *)this)->length)),data_alignment);
40 critical_error("Invalid header in size",(cell)this);
41 return 0; /* can't happen */
45 inline cell object::size() const
47 return size(no_fixup());
50 /* The number of cells from the start of the object which should be scanned by
51 the GC. Some types have a binary payload at the end (string, word, DLL) which
53 template<typename Fixup>
54 cell object::binary_payload_start(Fixup fixup) const
56 if(free_p()) return 0;
60 /* these objects do not refer to other objects at all */
66 /* these objects have some binary data at the end */
68 return sizeof(word) - sizeof(cell);
70 return sizeof(cell) * 3;
72 return sizeof(cell) * 2;
74 return sizeof(quotation) - sizeof(cell);
76 return sizeof(string);
77 /* everything else consists entirely of pointers */
79 return array_size<array>(array_capacity((array*)this));
82 tuple_layout *layout = (tuple_layout *)fixup.translate_data(untag<object>(((tuple *)this)->layout));
83 return tuple_size(layout);
86 return sizeof(wrapper);
88 critical_error("Invalid header in binary_payload_start",(cell)this);
89 return 0; /* can't happen */
93 inline cell object::binary_payload_start() const
95 return binary_payload_start(no_fixup());
98 /* Slot visitors iterate over the slots of an object, applying a functor to
99 each one that is a non-immediate slot. The pointer is untagged first. The
100 functor returns a new untagged object pointer. The return value may or may not equal the old one,
101 however the new pointer receives the same tag before being stored back to the
104 Slots storing immediate values are left unchanged and the visitor does inspect
107 This is used by GC's copying, sweep and compact phases, and the implementation
108 of the become primitive.
110 Iteration is driven by visit_*() methods. Some of them define GC roots:
112 - visit_contexts() */
114 template<typename Fixup> struct slot_visitor {
118 explicit slot_visitor<Fixup>(factor_vm *parent_, Fixup fixup_) :
119 parent(parent_), fixup(fixup_) {}
121 cell visit_pointer(cell pointer);
122 void visit_handle(cell *handle);
123 void visit_object_array(cell *start, cell *end);
124 void visit_slots(object *ptr, cell payload_start);
125 void visit_slots(object *ptr);
126 void visit_stack_elements(segment *region, cell *top);
127 void visit_data_roots();
128 void visit_bignum_roots();
129 void visit_callback_roots();
130 void visit_literal_table_roots();
132 void visit_callstack_object(callstack *stack);
133 void visit_callstack(context *ctx);
134 void visit_contexts();
135 void visit_code_block_objects(code_block *compiled);
136 void visit_embedded_literals(code_block *compiled);
137 void visit_sample_callstacks();
138 void visit_sample_threads();
141 template<typename Fixup>
142 cell slot_visitor<Fixup>::visit_pointer(cell pointer)
144 if(immediate_p(pointer)) return pointer;
146 object *untagged = fixup.fixup_data(untag<object>(pointer));
147 return RETAG(untagged,TAG(pointer));
150 template<typename Fixup>
151 void slot_visitor<Fixup>::visit_handle(cell *handle)
153 *handle = visit_pointer(*handle);
156 template<typename Fixup>
157 void slot_visitor<Fixup>::visit_object_array(cell *start, cell *end)
159 while(start < end) visit_handle(start++);
162 template<typename Fixup>
163 void slot_visitor<Fixup>::visit_slots(object *ptr, cell payload_start)
165 cell *slot = (cell *)ptr;
166 cell *end = (cell *)((cell)ptr + payload_start);
171 visit_object_array(slot,end);
175 template<typename Fixup>
176 void slot_visitor<Fixup>::visit_slots(object *obj)
178 if(obj->type() == CALLSTACK_TYPE)
179 visit_callstack_object((callstack *)obj);
181 visit_slots(obj,obj->binary_payload_start(fixup));
184 template<typename Fixup>
185 void slot_visitor<Fixup>::visit_stack_elements(segment *region, cell *top)
187 visit_object_array((cell *)region->start,top + 1);
190 template<typename Fixup>
191 void slot_visitor<Fixup>::visit_data_roots()
193 std::vector<data_root_range>::const_iterator iter = parent->data_roots.begin();
194 std::vector<data_root_range>::const_iterator end = parent->data_roots.end();
196 for(; iter < end; iter++)
197 visit_object_array(iter->start,iter->start + iter->len);
200 template<typename Fixup>
201 void slot_visitor<Fixup>::visit_bignum_roots()
203 std::vector<cell>::const_iterator iter = parent->bignum_roots.begin();
204 std::vector<cell>::const_iterator end = parent->bignum_roots.end();
206 for(; iter < end; iter++)
208 cell *handle = (cell *)(*iter);
211 *handle = (cell)fixup.fixup_data(*(object **)handle);
215 template<typename Fixup>
216 struct callback_slot_visitor {
217 callback_heap *callbacks;
218 slot_visitor<Fixup> *visitor;
220 explicit callback_slot_visitor(callback_heap *callbacks_, slot_visitor<Fixup> *visitor_) :
221 callbacks(callbacks_), visitor(visitor_) {}
223 void operator()(code_block *stub)
225 visitor->visit_handle(&stub->owner);
229 template<typename Fixup>
230 void slot_visitor<Fixup>::visit_callback_roots()
232 callback_slot_visitor<Fixup> callback_visitor(parent->callbacks,this);
233 parent->callbacks->each_callback(callback_visitor);
236 template<typename Fixup>
237 void slot_visitor<Fixup>::visit_literal_table_roots()
239 std::map<code_block *, cell> *uninitialized_blocks = &parent->code->uninitialized_blocks;
240 std::map<code_block *, cell>::const_iterator iter = uninitialized_blocks->begin();
241 std::map<code_block *, cell>::const_iterator end = uninitialized_blocks->end();
243 std::map<code_block *, cell> new_uninitialized_blocks;
244 for(; iter != end; iter++)
246 new_uninitialized_blocks.insert(std::make_pair(
248 visit_pointer(iter->second)));
251 parent->code->uninitialized_blocks = new_uninitialized_blocks;
254 template<typename Fixup>
255 void slot_visitor<Fixup>::visit_sample_callstacks()
257 for (std::vector<cell>::iterator iter = parent->sample_callstacks.begin();
258 iter != parent->sample_callstacks.end();
261 visit_handle(&*iter);
265 template<typename Fixup>
266 void slot_visitor<Fixup>::visit_sample_threads()
268 for (std::vector<profiling_sample>::iterator iter = parent->samples.begin();
269 iter != parent->samples.end();
272 visit_handle(&iter->thread);
276 template<typename Fixup>
277 void slot_visitor<Fixup>::visit_roots()
279 visit_handle(&parent->true_object);
280 visit_handle(&parent->bignum_zero);
281 visit_handle(&parent->bignum_pos_one);
282 visit_handle(&parent->bignum_neg_one);
285 visit_bignum_roots();
286 visit_callback_roots();
287 visit_literal_table_roots();
288 visit_sample_callstacks();
289 visit_sample_threads();
291 visit_object_array(parent->special_objects,parent->special_objects + special_object_count);
294 template<typename Fixup>
295 struct call_frame_slot_visitor {
297 slot_visitor<Fixup> *visitor;
299 explicit call_frame_slot_visitor(factor_vm *parent_, slot_visitor<Fixup> *visitor_) :
300 parent(parent_), visitor(visitor_) {}
303 next -> [entry_point]
305 [return address] -- x86 only, backend adds 1 to each spill location
308 frame -> [entry_point]
311 void operator()(stack_frame *frame)
313 cell return_address = parent->frame_offset(frame);
314 if(return_address == (cell)-1)
317 code_block *compiled = visitor->fixup.translate_code(parent->frame_code(frame));
318 gc_info *info = compiled->block_gc_info();
320 FACTOR_ASSERT(return_address < compiled->size());
321 cell callsite = info->return_address_index(return_address);
322 if(callsite == (cell)-1)
326 std::cout << "call frame code block " << compiled << " with offset " << return_address << std::endl;
328 cell *stack_pointer = (cell *)(parent->frame_successor(frame) + 1);
329 u8 *bitmap = info->gc_info_bitmap();
331 /* Subtract old value of base pointer from every derived pointer. */
332 for(cell spill_slot = 0; spill_slot < info->derived_root_count; spill_slot++)
334 u32 base_pointer = info->lookup_base_pointer(callsite, spill_slot);
335 if(base_pointer != (u32)-1)
338 std::cout << "visiting derived root " << spill_slot
339 << " with base pointer " << base_pointer
342 stack_pointer[spill_slot] -= stack_pointer[base_pointer];
346 /* Update all GC roots, including base pointers. */
347 cell callsite_gc_roots = info->callsite_gc_roots(callsite);
349 for(cell spill_slot = 0; spill_slot < info->gc_root_count; spill_slot++)
351 if(bitmap_p(bitmap,callsite_gc_roots + spill_slot))
354 std::cout << "visiting GC root " << spill_slot << std::endl;
356 visitor->visit_handle(stack_pointer + spill_slot);
360 /* Add the base pointers to obtain new derived pointer values. */
361 for(cell spill_slot = 0; spill_slot < info->derived_root_count; spill_slot++)
363 u32 base_pointer = info->lookup_base_pointer(callsite, spill_slot);
364 if(base_pointer != (u32)-1)
365 stack_pointer[spill_slot] += stack_pointer[base_pointer];
370 template<typename Fixup>
371 void slot_visitor<Fixup>::visit_callstack_object(callstack *stack)
373 call_frame_slot_visitor<Fixup> call_frame_visitor(parent,this);
374 parent->iterate_callstack_object(stack,call_frame_visitor);
377 template<typename Fixup>
378 void slot_visitor<Fixup>::visit_callstack(context *ctx)
380 call_frame_slot_visitor<Fixup> call_frame_visitor(parent,this);
381 parent->iterate_callstack(ctx,call_frame_visitor);
384 template<typename Fixup>
385 void slot_visitor<Fixup>::visit_contexts()
387 std::set<context *>::const_iterator begin = parent->active_contexts.begin();
388 std::set<context *>::const_iterator end = parent->active_contexts.end();
391 context *ctx = *begin;
393 visit_stack_elements(ctx->datastack_seg,(cell *)ctx->datastack);
394 visit_stack_elements(ctx->retainstack_seg,(cell *)ctx->retainstack);
395 visit_object_array(ctx->context_objects,ctx->context_objects + context_object_count);
396 visit_callstack(ctx);
401 template<typename Fixup>
402 struct literal_references_visitor {
403 slot_visitor<Fixup> *visitor;
405 explicit literal_references_visitor(slot_visitor<Fixup> *visitor_) : visitor(visitor_) {}
407 void operator()(instruction_operand op)
409 if(op.rel_type() == RT_LITERAL)
410 op.store_value(visitor->visit_pointer(op.load_value()));
414 template<typename Fixup>
415 void slot_visitor<Fixup>::visit_code_block_objects(code_block *compiled)
417 visit_handle(&compiled->owner);
418 visit_handle(&compiled->parameters);
419 visit_handle(&compiled->relocation);
422 template<typename Fixup>
423 void slot_visitor<Fixup>::visit_embedded_literals(code_block *compiled)
425 if(!parent->code->uninitialized_p(compiled))
427 literal_references_visitor<Fixup> visitor(this);
428 compiled->each_instruction_operand(visitor);