]> gitweb.factorcode.org Git - factor.git/blob - vm/code_block_visitor.hpp
GC maps for more compact inline GC checks
[factor.git] / vm / code_block_visitor.hpp
1 namespace factor
2 {
3
4 /* Code block visitors iterate over sets of code blocks, applying a functor to
5 each one. The functor returns a new code_block pointer, which may or may not
6 equal the old one. This is stored back to the original location.
7
8 This is used by GC's sweep and compact phases, and the implementation of the
9 modify-code-heap primitive.
10
11 Iteration is driven by visit_*() methods. Some of them define GC roots:
12 - visit_context_code_blocks()
13 - visit_callback_code_blocks() */
14  
15 template<typename Fixup> struct code_block_visitor {
16         factor_vm *parent;
17         Fixup fixup;
18
19         explicit code_block_visitor(factor_vm *parent_, Fixup fixup_) :
20                 parent(parent_), fixup(fixup_) {}
21
22         code_block *visit_code_block(code_block *compiled);
23         void visit_object_code_block(object *obj);
24         void visit_embedded_code_pointers(code_block *compiled);
25         void visit_context_code_blocks();
26         void visit_uninitialized_code_blocks();
27 };
28
29 template<typename Fixup>
30 code_block *code_block_visitor<Fixup>::visit_code_block(code_block *compiled)
31 {
32         return fixup.fixup_code(compiled);
33 }
34
35 template<typename Fixup>
36 struct call_frame_code_block_visitor {
37         factor_vm *parent;
38         Fixup fixup;
39
40         explicit call_frame_code_block_visitor(factor_vm *parent_, Fixup fixup_) :
41                 parent(parent_), fixup(fixup_) {}
42
43         void operator()(stack_frame *frame)
44         {
45                 code_block *old_block = parent->frame_code(frame);
46                 cell offset = (char *)FRAME_RETURN_ADDRESS(frame,parent) - (char *)old_block;
47
48                 const code_block *new_block = fixup.fixup_code(old_block);
49                 frame->entry_point = new_block->entry_point();
50
51                 FRAME_RETURN_ADDRESS(frame,parent) = (char *)new_block + offset;
52         }
53 };
54
55 template<typename Fixup>
56 void code_block_visitor<Fixup>::visit_object_code_block(object *obj)
57 {
58         switch(obj->type())
59         {
60         case WORD_TYPE:
61                 {
62                         word *w = (word *)obj;
63                         if(w->code)
64                                 w->code = visit_code_block(w->code);
65                         if(w->profiling)
66                                 w->profiling = visit_code_block(w->profiling);
67
68                         parent->update_word_entry_point(w);
69                         break;
70                 }
71         case QUOTATION_TYPE:
72                 {
73                         quotation *q = (quotation *)obj;
74                         if(q->code)
75                                 parent->set_quot_entry_point(q,visit_code_block(q->code));
76                         break;
77                 }
78         case CALLSTACK_TYPE:
79                 {
80                         callstack *stack = (callstack *)obj;
81                         call_frame_code_block_visitor<Fixup> call_frame_visitor(parent,fixup);
82                         parent->iterate_callstack_object(stack,call_frame_visitor);
83                         break;
84                 }
85         }
86 }
87
88 template<typename Fixup>
89 struct embedded_code_pointers_visitor {
90         Fixup fixup;
91
92         explicit embedded_code_pointers_visitor(Fixup fixup_) : fixup(fixup_) {}
93
94         void operator()(instruction_operand op)
95         {
96                 relocation_type type = op.rel_type();
97                 if(type == RT_ENTRY_POINT
98                         || type == RT_ENTRY_POINT_PIC
99                         || type == RT_ENTRY_POINT_PIC_TAIL)
100                         op.store_code_block(fixup.fixup_code(op.load_code_block()));
101         }
102 };
103
104 template<typename Fixup>
105 void code_block_visitor<Fixup>::visit_embedded_code_pointers(code_block *compiled)
106 {
107         if(!parent->code->uninitialized_p(compiled))
108         {
109                 embedded_code_pointers_visitor<Fixup> operand_visitor(fixup);
110                 compiled->each_instruction_operand(operand_visitor);
111         }
112 }
113
114 template<typename Fixup>
115 void code_block_visitor<Fixup>::visit_context_code_blocks()
116 {
117         call_frame_code_block_visitor<Fixup> call_frame_visitor(parent,fixup);
118         parent->iterate_active_callstacks(call_frame_visitor);
119 }
120
121 template<typename Fixup>
122 void code_block_visitor<Fixup>::visit_uninitialized_code_blocks()
123 {
124         std::map<code_block *, cell> *uninitialized_blocks = &parent->code->uninitialized_blocks;
125         std::map<code_block *, cell>::const_iterator iter = uninitialized_blocks->begin();
126         std::map<code_block *, cell>::const_iterator end = uninitialized_blocks->end();
127
128         std::map<code_block *, cell> new_uninitialized_blocks;
129         for(; iter != end; iter++)
130         {
131                 new_uninitialized_blocks.insert(std::make_pair(
132                         fixup.fixup_code(iter->first),
133                         iter->second));
134         }
135
136         parent->code->uninitialized_blocks = new_uninitialized_blocks;
137 }
138
139 }