]> gitweb.factorcode.org Git - factor.git/blob - vm/code_block_visitor.hpp
8b48d3672f8f38a142fcefaed54e606bd5eac72e
[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                 cell offset = parent->frame_offset(frame);
46                 code_block *compiled = fixup.fixup_code(parent->frame_code(frame));
47                 frame->entry_point = compiled->entry_point();
48                 parent->set_frame_offset(frame,offset);
49         }
50 };
51
52 template<typename Fixup>
53 void code_block_visitor<Fixup>::visit_object_code_block(object *obj)
54 {
55         switch(obj->type())
56         {
57         case WORD_TYPE:
58                 {
59                         word *w = (word *)obj;
60                         if(w->code)
61                                 w->code = visit_code_block(w->code);
62                         if(w->profiling)
63                                 w->profiling = visit_code_block(w->profiling);
64
65                         parent->update_word_entry_point(w);
66                         break;
67                 }
68         case QUOTATION_TYPE:
69                 {
70                         quotation *q = (quotation *)obj;
71                         if(q->code)
72                                 parent->set_quot_entry_point(q,visit_code_block(q->code));
73                         break;
74                 }
75         case CALLSTACK_TYPE:
76                 {
77                         callstack *stack = (callstack *)obj;
78                         call_frame_code_block_visitor<Fixup> call_frame_visitor(parent,fixup);
79                         parent->iterate_callstack_object(stack,call_frame_visitor);
80                         break;
81                 }
82         }
83 }
84
85 template<typename Fixup>
86 struct embedded_code_pointers_visitor {
87         Fixup fixup;
88
89         explicit embedded_code_pointers_visitor(Fixup fixup_) : fixup(fixup_) {}
90
91         void operator()(instruction_operand op)
92         {
93                 relocation_type type = op.rel_type();
94                 if(type == RT_ENTRY_POINT
95                         || type == RT_ENTRY_POINT_PIC
96                         || type == RT_ENTRY_POINT_PIC_TAIL)
97                         op.store_code_block(fixup.fixup_code(op.load_code_block()));
98         }
99 };
100
101 template<typename Fixup>
102 void code_block_visitor<Fixup>::visit_embedded_code_pointers(code_block *compiled)
103 {
104         if(!parent->code->uninitialized_p(compiled))
105         {
106                 embedded_code_pointers_visitor<Fixup> operand_visitor(fixup);
107                 compiled->each_instruction_operand(operand_visitor);
108         }
109 }
110
111 template<typename Fixup>
112 void code_block_visitor<Fixup>::visit_context_code_blocks()
113 {
114         call_frame_code_block_visitor<Fixup> call_frame_visitor(parent,fixup);
115         parent->iterate_active_callstacks(call_frame_visitor);
116 }
117
118 template<typename Fixup>
119 void code_block_visitor<Fixup>::visit_uninitialized_code_blocks()
120 {
121         std::map<code_block *, cell> *uninitialized_blocks = &parent->code->uninitialized_blocks;
122         std::map<code_block *, cell>::const_iterator iter = uninitialized_blocks->begin();
123         std::map<code_block *, cell>::const_iterator end = uninitialized_blocks->end();
124
125         std::map<code_block *, cell> new_uninitialized_blocks;
126         for(; iter != end; iter++)
127         {
128                 new_uninitialized_blocks.insert(std::make_pair(
129                         fixup.fixup_code(iter->first),
130                         iter->second));
131         }
132
133         parent->code->uninitialized_blocks = new_uninitialized_blocks;
134 }
135
136 }