5 template<typename Block> struct forwarder {
6 mark_bits<Block> *forwarding_map;
8 explicit forwarder(mark_bits<Block> *forwarding_map_) :
9 forwarding_map(forwarding_map_) {}
11 Block *operator()(Block *block)
13 return forwarding_map->forward_block(block);
17 static inline cell tuple_size_with_forwarding(mark_bits<object> *forwarding_map, object *obj)
19 /* The tuple layout may or may not have been forwarded already. Tricky. */
20 object *layout_obj = (object *)UNTAG(((tuple *)obj)->layout);
25 /* It's already been moved up; dereference through forwarding
26 map to get the size */
27 layout = (tuple_layout *)forwarding_map->forward_block(layout_obj);
31 /* It hasn't been moved up yet; dereference directly */
32 layout = (tuple_layout *)layout_obj;
35 return tuple_size(layout);
38 struct compaction_sizer {
39 mark_bits<object> *forwarding_map;
41 explicit compaction_sizer(mark_bits<object> *forwarding_map_) :
42 forwarding_map(forwarding_map_) {}
44 cell operator()(object *obj)
46 if(!forwarding_map->marked_p(obj))
47 return forwarding_map->unmarked_block_size(obj);
48 else if(obj->type() == TUPLE_TYPE)
49 return align(tuple_size_with_forwarding(forwarding_map,obj),data_alignment);
55 struct object_compaction_updater {
57 mark_bits<code_block> *code_forwarding_map;
58 mark_bits<object> *data_forwarding_map;
59 object_start_map *starts;
61 explicit object_compaction_updater(factor_vm *parent_,
62 mark_bits<object> *data_forwarding_map_,
63 mark_bits<code_block> *code_forwarding_map_) :
65 code_forwarding_map(code_forwarding_map_),
66 data_forwarding_map(data_forwarding_map_),
67 starts(&parent->data->tenured->starts) {}
69 void operator()(object *old_address, object *new_address, cell size)
72 if(old_address->type() == TUPLE_TYPE)
73 payload_start = tuple_size_with_forwarding(data_forwarding_map,old_address);
75 payload_start = old_address->binary_payload_start();
77 memmove(new_address,old_address,size);
79 slot_visitor<forwarder<object> > slot_forwarder(parent,forwarder<object>(data_forwarding_map));
80 slot_forwarder.visit_slots(new_address,payload_start);
82 code_block_visitor<forwarder<code_block> > code_forwarder(parent,forwarder<code_block>(code_forwarding_map));
83 code_forwarder.visit_object_code_block(new_address);
85 starts->record_object_start_offset(new_address);
89 template<typename SlotForwarder>
90 struct code_block_compaction_relocation_visitor {
92 code_block *old_address;
93 slot_visitor<SlotForwarder> slot_forwarder;
94 code_block_visitor<forwarder<code_block> > code_forwarder;
96 explicit code_block_compaction_relocation_visitor(factor_vm *parent_,
97 code_block *old_address_,
98 slot_visitor<SlotForwarder> slot_forwarder_,
99 code_block_visitor<forwarder<code_block> > code_forwarder_) :
101 old_address(old_address_),
102 slot_forwarder(slot_forwarder_),
103 code_forwarder(code_forwarder_) {}
105 void operator()(instruction_operand op)
107 cell old_offset = op.rel_offset() + (cell)old_address->entry_point();
109 switch(op.rel_type())
112 op.store_value(slot_forwarder.visit_pointer(op.load_value(old_offset)));
115 op.store_float(slot_forwarder.visit_pointer(op.load_float(old_offset)));
118 case RT_ENTRY_POINT_PIC:
119 case RT_ENTRY_POINT_PIC_TAIL:
120 op.store_code_block(code_forwarder.visit_code_block(op.load_code_block(old_offset)));
123 op.store_value(op.load_value(old_offset) - (cell)old_address + (cell)op.parent_code_block());
126 case RT_CARDS_OFFSET:
127 case RT_DECKS_OFFSET:
128 parent->store_external_address(op);
131 op.store_value(op.load_value(old_offset));
137 template<typename SlotForwarder>
138 struct code_block_compaction_updater {
140 slot_visitor<SlotForwarder> slot_forwarder;
141 code_block_visitor<forwarder<code_block> > code_forwarder;
143 explicit code_block_compaction_updater(factor_vm *parent_,
144 slot_visitor<SlotForwarder> slot_forwarder_,
145 code_block_visitor<forwarder<code_block> > code_forwarder_) :
147 slot_forwarder(slot_forwarder_),
148 code_forwarder(code_forwarder_) {}
150 void operator()(code_block *old_address, code_block *new_address, cell size)
152 memmove(new_address,old_address,size);
154 slot_forwarder.visit_code_block_objects(new_address);
156 code_block_compaction_relocation_visitor<SlotForwarder> visitor(parent,old_address,slot_forwarder,code_forwarder);
157 new_address->each_instruction_operand(visitor);
161 /* After a compaction, invalidate any code heap roots which are not
162 marked, and also slide the valid roots up so that call sites can be updated
163 correctly in case an inline cache compilation triggered compaction. */
164 void factor_vm::update_code_roots_for_compaction()
166 std::vector<code_root *>::const_iterator iter = code_roots.begin();
167 std::vector<code_root *>::const_iterator end = code_roots.end();
169 mark_bits<code_block> *state = &code->allocator->state;
171 for(; iter < end; iter++)
173 code_root *root = *iter;
174 code_block *block = (code_block *)(root->value & (~data_alignment + 1));
176 /* Offset of return address within 16-byte allocation line */
177 cell offset = root->value - (cell)block;
179 if(root->valid && state->marked_p(block))
181 block = state->forward_block(block);
182 root->value = (cell)block + offset;
189 /* Compact data and code heaps */
190 void factor_vm::collect_compact_impl(bool trace_contexts_p)
192 current_gc->event->started_compaction();
194 tenured_space *tenured = data->tenured;
195 mark_bits<object> *data_forwarding_map = &tenured->state;
196 mark_bits<code_block> *code_forwarding_map = &code->allocator->state;
198 /* Figure out where blocks are going to go */
199 data_forwarding_map->compute_forwarding();
200 code_forwarding_map->compute_forwarding();
202 slot_visitor<forwarder<object> > slot_forwarder(this,forwarder<object>(data_forwarding_map));
203 code_block_visitor<forwarder<code_block> > code_forwarder(this,forwarder<code_block>(code_forwarding_map));
205 code_forwarder.visit_uninitialized_code_blocks();
207 /* Object start offsets get recomputed by the object_compaction_updater */
208 data->tenured->starts.clear_object_start_offsets();
210 /* Slide everything in tenured space up, and update data and code heap
211 pointers inside objects. */
212 object_compaction_updater object_updater(this,data_forwarding_map,code_forwarding_map);
213 compaction_sizer object_sizer(data_forwarding_map);
214 tenured->compact(object_updater,object_sizer);
216 /* Slide everything in the code heap up, and update data and code heap
217 pointers inside code blocks. */
218 code_block_compaction_updater<forwarder<object> > code_block_updater(this,slot_forwarder,code_forwarder);
219 standard_sizer<code_block> code_block_sizer;
220 code->allocator->compact(code_block_updater,code_block_sizer);
222 slot_forwarder.visit_roots();
225 slot_forwarder.visit_contexts();
226 code_forwarder.visit_context_code_blocks();
229 update_code_roots_for_compaction();
232 current_gc->event->ended_compaction();
235 struct object_grow_heap_updater {
236 code_block_visitor<forwarder<code_block> > code_forwarder;
238 explicit object_grow_heap_updater(code_block_visitor<forwarder<code_block> > code_forwarder_) :
239 code_forwarder(code_forwarder_) {}
241 void operator()(object *obj)
243 code_forwarder.visit_object_code_block(obj);
247 struct dummy_slot_forwarder {
248 object *operator()(object *obj) { return obj; }
251 /* Compact just the code heap, after growing the data heap */
252 void factor_vm::collect_compact_code_impl(bool trace_contexts_p)
254 /* Figure out where blocks are going to go */
255 mark_bits<code_block> *code_forwarding_map = &code->allocator->state;
256 code_forwarding_map->compute_forwarding();
258 slot_visitor<dummy_slot_forwarder> slot_forwarder(this,dummy_slot_forwarder());
259 code_block_visitor<forwarder<code_block> > code_forwarder(this,forwarder<code_block>(code_forwarding_map));
261 code_forwarder.visit_uninitialized_code_blocks();
264 code_forwarder.visit_context_code_blocks();
266 /* Update code heap references in data heap */
267 object_grow_heap_updater updater(code_forwarder);
268 each_object(updater);
270 /* Slide everything in the code heap up, and update code heap
271 pointers inside code blocks. */
272 code_block_compaction_updater<dummy_slot_forwarder> code_block_updater(this,slot_forwarder,code_forwarder);
273 standard_sizer<code_block> code_block_sizer;
274 code->allocator->compact(code_block_updater,code_block_sizer);
276 update_code_roots_for_compaction();
280 void factor_vm::collect_compact(bool trace_contexts_p)
282 collect_mark_impl(trace_contexts_p);
283 collect_compact_impl(trace_contexts_p);
284 code->flush_icache();
287 void factor_vm::collect_growing_heap(cell requested_bytes, bool trace_contexts_p)
289 /* Grow the data heap and copy all live objects to the new heap. */
290 data_heap *old = data;
291 set_data_heap(data->grow(requested_bytes));
292 collect_mark_impl(trace_contexts_p);
293 collect_compact_code_impl(trace_contexts_p);
294 code->flush_icache();