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) * 3;
70 return sizeof(cell) * 3;
72 return sizeof(cell) * 2;
74 return sizeof(quotation) - sizeof(cell) * 2;
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);
139 template<typename Fixup>
140 cell slot_visitor<Fixup>::visit_pointer(cell pointer)
142 if(immediate_p(pointer)) return pointer;
144 object *untagged = fixup.fixup_data(untag<object>(pointer));
145 return RETAG(untagged,TAG(pointer));
148 template<typename Fixup>
149 void slot_visitor<Fixup>::visit_handle(cell *handle)
151 *handle = visit_pointer(*handle);
154 template<typename Fixup>
155 void slot_visitor<Fixup>::visit_object_array(cell *start, cell *end)
157 while(start < end) visit_handle(start++);
160 template<typename Fixup>
161 void slot_visitor<Fixup>::visit_slots(object *ptr, cell payload_start)
163 cell *slot = (cell *)ptr;
164 cell *end = (cell *)((cell)ptr + payload_start);
169 visit_object_array(slot,end);
173 template<typename Fixup>
174 void slot_visitor<Fixup>::visit_slots(object *obj)
176 if(obj->type() == CALLSTACK_TYPE)
177 visit_callstack_object((callstack *)obj);
179 visit_slots(obj,obj->binary_payload_start(fixup));
182 template<typename Fixup>
183 void slot_visitor<Fixup>::visit_stack_elements(segment *region, cell *top)
185 visit_object_array((cell *)region->start,top + 1);
188 template<typename Fixup>
189 void slot_visitor<Fixup>::visit_data_roots()
191 std::vector<data_root_range>::const_iterator iter = parent->data_roots.begin();
192 std::vector<data_root_range>::const_iterator end = parent->data_roots.end();
194 for(; iter < end; iter++)
195 visit_object_array(iter->start,iter->start + iter->len);
198 template<typename Fixup>
199 void slot_visitor<Fixup>::visit_bignum_roots()
201 std::vector<cell>::const_iterator iter = parent->bignum_roots.begin();
202 std::vector<cell>::const_iterator end = parent->bignum_roots.end();
204 for(; iter < end; iter++)
206 cell *handle = (cell *)(*iter);
209 *handle = (cell)fixup.fixup_data(*(object **)handle);
213 template<typename Fixup>
214 struct callback_slot_visitor {
215 callback_heap *callbacks;
216 slot_visitor<Fixup> *visitor;
218 explicit callback_slot_visitor(callback_heap *callbacks_, slot_visitor<Fixup> *visitor_) :
219 callbacks(callbacks_), visitor(visitor_) {}
221 void operator()(code_block *stub)
223 visitor->visit_handle(&stub->owner);
227 template<typename Fixup>
228 void slot_visitor<Fixup>::visit_callback_roots()
230 callback_slot_visitor<Fixup> callback_visitor(parent->callbacks,this);
231 parent->callbacks->each_callback(callback_visitor);
234 template<typename Fixup>
235 void slot_visitor<Fixup>::visit_literal_table_roots()
237 std::map<code_block *, cell> *uninitialized_blocks = &parent->code->uninitialized_blocks;
238 std::map<code_block *, cell>::const_iterator iter = uninitialized_blocks->begin();
239 std::map<code_block *, cell>::const_iterator end = uninitialized_blocks->end();
241 std::map<code_block *, cell> new_uninitialized_blocks;
242 for(; iter != end; iter++)
244 new_uninitialized_blocks.insert(std::make_pair(
246 visit_pointer(iter->second)));
249 parent->code->uninitialized_blocks = new_uninitialized_blocks;
252 template<typename Fixup>
253 void slot_visitor<Fixup>::visit_roots()
255 visit_handle(&parent->true_object);
256 visit_handle(&parent->bignum_zero);
257 visit_handle(&parent->bignum_pos_one);
258 visit_handle(&parent->bignum_neg_one);
261 visit_bignum_roots();
262 visit_callback_roots();
263 visit_literal_table_roots();
265 visit_object_array(parent->special_objects,parent->special_objects + special_object_count);
268 template<typename Fixup>
269 struct call_frame_slot_visitor {
271 slot_visitor<Fixup> *visitor;
273 explicit call_frame_slot_visitor(factor_vm *parent_, slot_visitor<Fixup> *visitor_) :
274 parent(parent_), visitor(visitor_) {}
277 next -> [entry_point]
279 [return address] -- x86 only, backend adds 1 to each spill location
282 frame -> [entry_point]
285 void operator()(stack_frame *frame)
287 cell return_address = parent->frame_offset(frame);
288 if(return_address == (cell)-1)
291 code_block *compiled = visitor->fixup.translate_code(parent->frame_code(frame));
292 gc_info *info = compiled->block_gc_info();
294 assert(return_address < compiled->size());
295 int index = info->return_address_index(return_address);
300 std::cout << "call frame code block " << compiled << " with offset " << return_address << std::endl;
302 u8 *bitmap = info->gc_info_bitmap();
303 cell base = info->spill_slot_base(index);
304 cell *stack_pointer = (cell *)(parent->frame_successor(frame) + 1);
306 for(int spill_slot = 0; spill_slot < info->gc_root_count; spill_slot++)
308 if(bitmap_p(bitmap,base + spill_slot))
311 std::cout << "visiting spill slot " << spill_slot << std::endl;
313 visitor->visit_handle(stack_pointer + spill_slot);
319 template<typename Fixup>
320 void slot_visitor<Fixup>::visit_callstack_object(callstack *stack)
322 call_frame_slot_visitor<Fixup> call_frame_visitor(parent,this);
323 parent->iterate_callstack_object(stack,call_frame_visitor);
326 template<typename Fixup>
327 void slot_visitor<Fixup>::visit_callstack(context *ctx)
329 call_frame_slot_visitor<Fixup> call_frame_visitor(parent,this);
330 parent->iterate_callstack(ctx,call_frame_visitor);
333 template<typename Fixup>
334 void slot_visitor<Fixup>::visit_contexts()
336 std::set<context *>::const_iterator begin = parent->active_contexts.begin();
337 std::set<context *>::const_iterator end = parent->active_contexts.end();
340 context *ctx = *begin;
342 visit_stack_elements(ctx->datastack_seg,(cell *)ctx->datastack);
343 visit_stack_elements(ctx->retainstack_seg,(cell *)ctx->retainstack);
344 visit_object_array(ctx->context_objects,ctx->context_objects + context_object_count);
345 visit_callstack(ctx);
350 template<typename Fixup>
351 struct literal_references_visitor {
352 slot_visitor<Fixup> *visitor;
354 explicit literal_references_visitor(slot_visitor<Fixup> *visitor_) : visitor(visitor_) {}
356 void operator()(instruction_operand op)
358 if(op.rel_type() == RT_LITERAL)
359 op.store_value(visitor->visit_pointer(op.load_value()));
363 template<typename Fixup>
364 void slot_visitor<Fixup>::visit_code_block_objects(code_block *compiled)
366 visit_handle(&compiled->owner);
367 visit_handle(&compiled->parameters);
368 visit_handle(&compiled->relocation);
371 template<typename Fixup>
372 void slot_visitor<Fixup>::visit_embedded_literals(code_block *compiled)
374 if(!parent->code->uninitialized_p(compiled))
376 literal_references_visitor<Fixup> visitor(this);
377 compiled->each_instruction_operand(visitor);