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()(code_block* stub) { visitor->visit_handle(&stub->owner); }
212 template <typename Fixup> void slot_visitor<Fixup>::visit_callback_roots() {
213 callback_slot_visitor<Fixup> callback_visitor(parent->callbacks, this);
214 parent->callbacks->each_callback(callback_visitor);
217 template <typename Fixup>
218 void slot_visitor<Fixup>::visit_literal_table_roots() {
219 std::map<code_block*, cell>* uninitialized_blocks =
220 &parent->code->uninitialized_blocks;
221 std::map<code_block*, cell>::const_iterator iter =
222 uninitialized_blocks->begin();
223 std::map<code_block*, cell>::const_iterator end = uninitialized_blocks->end();
225 std::map<code_block*, cell> new_uninitialized_blocks;
226 for (; iter != end; iter++) {
227 new_uninitialized_blocks.insert(
228 std::make_pair(iter->first, visit_pointer(iter->second)));
231 parent->code->uninitialized_blocks = new_uninitialized_blocks;
234 template <typename Fixup> void slot_visitor<Fixup>::visit_sample_callstacks() {
235 for (std::vector<cell>::iterator iter = parent->sample_callstacks.begin();
236 iter != parent->sample_callstacks.end(); ++iter) {
237 visit_handle(&*iter);
241 template <typename Fixup> void slot_visitor<Fixup>::visit_sample_threads() {
242 for (std::vector<profiling_sample>::iterator iter = parent->samples.begin();
243 iter != parent->samples.end(); ++iter) {
244 visit_handle(&iter->thread);
248 template <typename Fixup> void slot_visitor<Fixup>::visit_roots() {
249 visit_handle(&parent->true_object);
250 visit_handle(&parent->bignum_zero);
251 visit_handle(&parent->bignum_pos_one);
252 visit_handle(&parent->bignum_neg_one);
255 visit_bignum_roots();
256 visit_callback_roots();
257 visit_literal_table_roots();
258 visit_sample_callstacks();
259 visit_sample_threads();
261 visit_object_array(parent->special_objects,
262 parent->special_objects + special_object_count);
265 /* primitive_minor_gc() is invoked by inline GC checks, and it needs to fill in
266 uninitialized stack locations before actually calling the GC. See the
267 documentation in compiler.cfg.stacks.vacant for details.
269 So for each call frame:
271 - scrub some uninitialized locations
272 - trace some overinitialized locations
273 - trace roots in spill slots
275 template <typename Fixup> struct call_frame_slot_visitor {
277 slot_visitor<Fixup>* visitor;
278 /* NULL in case we're a visitor for a callstack object. */
281 void check_stack(cell stack, uint8_t* bitmap, cell base, uint32_t count) {
282 for (uint32_t loc = 0; loc < count; loc++) {
283 if (bitmap_p(bitmap, base + loc)) {
285 std::cout << "checking stack location " << loc << std::endl;
287 cell* value_ptr = ((cell*)stack + loc + 1);
288 visitor->visit_handle(value_ptr);
293 void scrub_stack(cell stack, uint8_t* bitmap, cell base, uint32_t count) {
294 for (cell loc = 0; loc < count; loc++) {
295 if (bitmap_p(bitmap, base + loc)) {
297 std::cout << "scrubbing stack location " << loc << std::endl;
299 *((cell*)stack - loc) = 0;
304 call_frame_slot_visitor(factor_vm* parent,
305 slot_visitor<Fixup>* visitor,
307 : parent(parent), visitor(visitor), ctx(ctx) {}
310 frame top -> [return address]
316 void operator()(void* frame_top, cell frame_size, code_block* owner,
318 cell return_address = owner->offset(addr);
320 code_block* compiled =
321 Fixup::translated_code_block_map ? owner
322 : visitor->fixup.translate_code(owner);
323 gc_info* info = compiled->block_gc_info();
325 FACTOR_ASSERT(return_address < compiled->size());
326 cell callsite = info->return_address_index(return_address);
327 if (callsite == (cell)-1)
331 std::cout << "call frame code block " << compiled << " with offset "
332 << return_address << std::endl;
334 cell* stack_pointer = (cell*)frame_top;
335 uint8_t* bitmap = info->gc_info_bitmap();
338 /* Scrub vacant stack locations. */
339 scrub_stack(ctx->datastack,
341 info->callsite_scrub_d(callsite),
342 info->scrub_d_count);
343 scrub_stack(ctx->retainstack,
345 info->callsite_scrub_r(callsite),
346 info->scrub_r_count);
348 /* Trace overinitialized stack locations. */
349 check_stack(ctx->datastack,
351 info->callsite_check_d(callsite),
352 info->check_d_count);
353 check_stack(ctx->retainstack,
355 info->callsite_check_r(callsite),
356 info->check_r_count);
359 /* Subtract old value of base pointer from every derived pointer. */
360 for (cell spill_slot = 0; spill_slot < info->derived_root_count;
362 uint32_t base_pointer = info->lookup_base_pointer(callsite, spill_slot);
363 if (base_pointer != (uint32_t)-1) {
365 std::cout << "visiting derived root " << spill_slot
366 << " with base pointer " << base_pointer << std::endl;
368 stack_pointer[spill_slot] -= stack_pointer[base_pointer];
372 /* Update all GC roots, including base pointers. */
373 cell callsite_gc_roots = info->callsite_gc_roots(callsite);
375 for (cell spill_slot = 0; spill_slot < info->gc_root_count; spill_slot++) {
376 if (bitmap_p(bitmap, callsite_gc_roots + spill_slot)) {
378 std::cout << "visiting GC root " << spill_slot << std::endl;
380 visitor->visit_handle(stack_pointer + spill_slot);
384 /* Add the base pointers to obtain new derived pointer values. */
385 for (cell spill_slot = 0; spill_slot < info->derived_root_count;
387 uint32_t base_pointer = info->lookup_base_pointer(callsite, spill_slot);
388 if (base_pointer != (uint32_t)-1)
389 stack_pointer[spill_slot] += stack_pointer[base_pointer];
394 template <typename Fixup>
395 void slot_visitor<Fixup>::visit_callstack_object(callstack* stack) {
396 call_frame_slot_visitor<Fixup> call_frame_visitor(parent, this, NULL);
397 parent->iterate_callstack_object(stack, call_frame_visitor, fixup);
400 template <typename Fixup>
401 void slot_visitor<Fixup>::visit_callstack(context* ctx) {
402 call_frame_slot_visitor<Fixup> call_frame_visitor(parent, this, ctx);
403 parent->iterate_callstack(ctx, call_frame_visitor, fixup);
406 template <typename Fixup>
407 void slot_visitor<Fixup>::visit_context(context* ctx) {
408 /* Callstack is visited first because it scrubs the data and retain
410 visit_callstack(ctx);
412 visit_stack_elements(ctx->datastack_seg, (cell*)ctx->datastack);
413 visit_stack_elements(ctx->retainstack_seg, (cell*)ctx->retainstack);
414 visit_object_array(ctx->context_objects,
415 ctx->context_objects + context_object_count);
419 template <typename Fixup> void slot_visitor<Fixup>::visit_contexts() {
420 std::set<context*>::const_iterator begin = parent->active_contexts.begin();
421 std::set<context*>::const_iterator end = parent->active_contexts.end();
422 while (begin != end) {
423 visit_context(*begin);
428 template <typename Fixup> struct literal_references_visitor {
429 slot_visitor<Fixup>* visitor;
431 explicit literal_references_visitor(slot_visitor<Fixup>* visitor)
432 : visitor(visitor) {}
434 void operator()(instruction_operand op) {
435 if (op.rel_type() == RT_LITERAL)
436 op.store_value(visitor->visit_pointer(op.load_value()));
440 template <typename Fixup>
441 void slot_visitor<Fixup>::visit_code_block_objects(code_block* compiled) {
442 visit_handle(&compiled->owner);
443 visit_handle(&compiled->parameters);
444 visit_handle(&compiled->relocation);
447 template <typename Fixup>
448 void slot_visitor<Fixup>::visit_embedded_literals(code_block* compiled) {
449 if (!parent->code->uninitialized_p(compiled)) {
450 literal_references_visitor<Fixup> visitor(this);
451 compiled->each_instruction_operand(visitor);