5 void factor_vm::update_fixup_set_for_compaction(mark_bits<code_block> *forwarding_map)
7 std::set<code_block *>::const_iterator iter = code->needs_fixup.begin();
8 std::set<code_block *>::const_iterator end = code->needs_fixup.end();
10 std::set<code_block *> new_needs_fixup;
11 for(; iter != end; iter++)
12 new_needs_fixup.insert(forwarding_map->forward_block(*iter));
14 code->needs_fixup = new_needs_fixup;
17 template<typename Block> struct forwarder {
18 mark_bits<Block> *forwarding_map;
20 explicit forwarder(mark_bits<Block> *forwarding_map_) :
21 forwarding_map(forwarding_map_) {}
23 Block *operator()(Block *block)
25 return forwarding_map->forward_block(block);
29 static inline cell tuple_size_with_forwarding(mark_bits<object> *forwarding_map, object *obj)
31 /* The tuple layout may or may not have been forwarded already. Tricky. */
32 object *layout_obj = (object *)UNTAG(((tuple *)obj)->layout);
37 /* It's already been moved up; dereference through forwarding
38 map to get the size */
39 layout = (tuple_layout *)forwarding_map->forward_block(layout_obj);
43 /* It hasn't been moved up yet; dereference directly */
44 layout = (tuple_layout *)layout_obj;
47 return tuple_size(layout);
50 struct compaction_sizer {
51 mark_bits<object> *forwarding_map;
53 explicit compaction_sizer(mark_bits<object> *forwarding_map_) :
54 forwarding_map(forwarding_map_) {}
56 cell operator()(object *obj)
58 if(!forwarding_map->marked_p(obj))
59 return forwarding_map->unmarked_block_size(obj);
60 else if(obj->type() == TUPLE_TYPE)
61 return align(tuple_size_with_forwarding(forwarding_map,obj),data_alignment);
67 struct object_compaction_updater {
69 mark_bits<code_block> *code_forwarding_map;
70 mark_bits<object> *data_forwarding_map;
71 object_start_map *starts;
73 explicit object_compaction_updater(factor_vm *parent_,
74 mark_bits<object> *data_forwarding_map_,
75 mark_bits<code_block> *code_forwarding_map_) :
77 code_forwarding_map(code_forwarding_map_),
78 data_forwarding_map(data_forwarding_map_),
79 starts(&parent->data->tenured->starts) {}
81 void operator()(object *old_address, object *new_address, cell size)
84 if(old_address->type() == TUPLE_TYPE)
85 payload_start = tuple_size_with_forwarding(data_forwarding_map,old_address);
87 payload_start = old_address->binary_payload_start();
89 memmove(new_address,old_address,size);
91 slot_visitor<forwarder<object> > slot_forwarder(parent,forwarder<object>(data_forwarding_map));
92 slot_forwarder.visit_slots(new_address,payload_start);
94 code_block_visitor<forwarder<code_block> > code_forwarder(parent,forwarder<code_block>(code_forwarding_map));
95 code_forwarder.visit_object_code_block(new_address);
97 starts->record_object_start_offset(new_address);
101 template<typename SlotForwarder>
102 struct code_block_compaction_relocation_visitor {
104 code_block *old_address;
105 slot_visitor<SlotForwarder> slot_forwarder;
106 code_block_visitor<forwarder<code_block> > code_forwarder;
108 explicit code_block_compaction_relocation_visitor(factor_vm *parent_,
109 code_block *old_address_,
110 slot_visitor<SlotForwarder> slot_forwarder_,
111 code_block_visitor<forwarder<code_block> > code_forwarder_) :
113 old_address(old_address_),
114 slot_forwarder(slot_forwarder_),
115 code_forwarder(code_forwarder_) {}
117 void operator()(instruction_operand op)
119 cell old_offset = op.rel_offset() + (cell)old_address->xt();
121 switch(op.rel_type())
124 op.store_value(slot_forwarder.visit_pointer(op.load_value(old_offset)));
129 op.store_code_block(code_forwarder.visit_code_block(op.load_code_block(old_offset)));
133 case RT_CARDS_OFFSET:
134 case RT_DECKS_OFFSET:
135 parent->store_external_address(op);
138 op.store_value(op.load_value(old_offset));
144 template<typename SlotForwarder>
145 struct code_block_compaction_updater {
147 slot_visitor<SlotForwarder> slot_forwarder;
148 code_block_visitor<forwarder<code_block> > code_forwarder;
150 explicit code_block_compaction_updater(factor_vm *parent_,
151 slot_visitor<SlotForwarder> slot_forwarder_,
152 code_block_visitor<forwarder<code_block> > code_forwarder_) :
154 slot_forwarder(slot_forwarder_),
155 code_forwarder(code_forwarder_) {}
157 void operator()(code_block *old_address, code_block *new_address, cell size)
159 memmove(new_address,old_address,size);
161 slot_forwarder.visit_code_block_objects(new_address);
163 code_block_compaction_relocation_visitor<SlotForwarder> visitor(parent,old_address,slot_forwarder,code_forwarder);
164 new_address->each_instruction_operand(visitor);
168 /* Compact data and code heaps */
169 void factor_vm::collect_compact_impl(bool trace_contexts_p)
171 current_gc->event->started_compaction();
173 tenured_space *tenured = data->tenured;
174 mark_bits<object> *data_forwarding_map = &tenured->state;
175 mark_bits<code_block> *code_forwarding_map = &code->allocator->state;
177 /* Figure out where blocks are going to go */
178 data_forwarding_map->compute_forwarding();
179 code_forwarding_map->compute_forwarding();
181 update_fixup_set_for_compaction(code_forwarding_map);
183 slot_visitor<forwarder<object> > slot_forwarder(this,forwarder<object>(data_forwarding_map));
184 code_block_visitor<forwarder<code_block> > code_forwarder(this,forwarder<code_block>(code_forwarding_map));
186 /* Object start offsets get recomputed by the object_compaction_updater */
187 data->tenured->starts.clear_object_start_offsets();
189 /* Slide everything in tenured space up, and update data and code heap
190 pointers inside objects. */
191 object_compaction_updater object_updater(this,data_forwarding_map,code_forwarding_map);
192 compaction_sizer object_sizer(data_forwarding_map);
193 tenured->compact(object_updater,object_sizer);
195 /* Slide everything in the code heap up, and update data and code heap
196 pointers inside code blocks. */
197 code_block_compaction_updater<forwarder<object> > code_block_updater(this,slot_forwarder,code_forwarder);
198 standard_sizer<code_block> code_block_sizer;
199 code->allocator->compact(code_block_updater,code_block_sizer);
201 slot_forwarder.visit_roots();
204 slot_forwarder.visit_contexts();
205 code_forwarder.visit_context_code_blocks();
208 update_code_roots_for_compaction();
211 current_gc->event->ended_compaction();
214 struct object_grow_heap_updater {
215 code_block_visitor<forwarder<code_block> > code_forwarder;
217 explicit object_grow_heap_updater(code_block_visitor<forwarder<code_block> > code_forwarder_) :
218 code_forwarder(code_forwarder_) {}
220 void operator()(object *obj)
222 code_forwarder.visit_object_code_block(obj);
226 struct dummy_slot_forwarder {
227 object *operator()(object *obj) { return obj; }
230 /* Compact just the code heap, after growing the data heap */
231 void factor_vm::collect_compact_code_impl(bool trace_contexts_p)
233 /* Figure out where blocks are going to go */
234 mark_bits<code_block> *code_forwarding_map = &code->allocator->state;
235 code_forwarding_map->compute_forwarding();
237 update_fixup_set_for_compaction(code_forwarding_map);
239 slot_visitor<dummy_slot_forwarder> slot_forwarder(this,dummy_slot_forwarder());
240 code_block_visitor<forwarder<code_block> > code_forwarder(this,forwarder<code_block>(code_forwarding_map));
243 code_forwarder.visit_context_code_blocks();
245 /* Update code heap references in data heap */
246 object_grow_heap_updater updater(code_forwarder);
247 each_object(updater);
249 /* Slide everything in the code heap up, and update code heap
250 pointers inside code blocks. */
251 code_block_compaction_updater<dummy_slot_forwarder> code_block_updater(this,slot_forwarder,code_forwarder);
252 standard_sizer<code_block> code_block_sizer;
253 code->allocator->compact(code_block_updater,code_block_sizer);
255 update_code_roots_for_compaction();
259 void factor_vm::collect_compact(bool trace_contexts_p)
261 collect_mark_impl(trace_contexts_p);
262 collect_compact_impl(trace_contexts_p);
263 code->flush_icache();
266 void factor_vm::collect_growing_heap(cell requested_bytes, bool trace_contexts_p)
268 /* Grow the data heap and copy all live objects to the new heap. */
269 data_heap *old = data;
270 set_data_heap(data->grow(requested_bytes));
271 collect_mark_impl(trace_contexts_p);
272 collect_compact_code_impl(trace_contexts_p);
273 code->flush_icache();