]> gitweb.factorcode.org Git - factor.git/blob - vm/callbacks.cpp
Merge remote-tracking branch 'ex-rzr/fixes'
[factor.git] / vm / callbacks.cpp
1 #include "master.hpp"
2
3 namespace factor
4 {
5
6 callback_heap::callback_heap(cell size, factor_vm *parent_) :
7         seg(new segment(size,true)),
8         here(seg->start),
9         parent(parent_) {}
10
11 callback_heap::~callback_heap()
12 {
13         delete seg;
14         seg = NULL;
15 }
16
17 void factor_vm::init_callbacks(cell size)
18 {
19         callbacks = new callback_heap(size,this);
20 }
21
22 bool callback_heap::setup_seh_p()
23 {
24 #if defined(WINDOWS) && defined(FACTOR_X86)
25         return true;
26 #else
27         return false;
28 #endif
29 }
30
31 bool callback_heap::return_takes_param_p()
32 {
33 #if defined(FACTOR_X86) || defined(FACTOR_AMD64)
34         return true;
35 #else
36         return false;
37 #endif
38 }
39
40 instruction_operand callback_heap::callback_operand(code_block *stub, cell index)
41 {
42         tagged<array> code_template(parent->special_objects[CALLBACK_STUB]);
43
44         cell rel_class = untag_fixnum(array_nth(code_template.untagged(),3 * index + 1));
45         cell rel_type  = untag_fixnum(array_nth(code_template.untagged(),3 * index + 2));
46         cell offset    = untag_fixnum(array_nth(code_template.untagged(),3 * index + 3));
47
48         relocation_entry rel(
49                 (relocation_type)rel_type,
50                 (relocation_class)rel_class,
51                 offset);
52
53         instruction_operand op(rel,stub,0);
54
55         return op;
56 }
57
58 void callback_heap::store_callback_operand(code_block *stub, cell index)
59 {
60         parent->store_external_address(callback_operand(stub,index));
61 }
62
63 void callback_heap::store_callback_operand(code_block *stub, cell index, cell value)
64 {
65         callback_operand(stub,index).store_value(value);
66 }
67
68 void callback_heap::update(code_block *stub)
69 {
70         store_callback_operand(stub,setup_seh_p() ? 2 : 1,(cell)callback_entry_point(stub));
71         stub->flush_icache();
72 }
73
74 code_block *callback_heap::add(cell owner, cell return_rewind)
75 {
76         tagged<array> code_template(parent->special_objects[CALLBACK_STUB]);
77         tagged<byte_array> insns(array_nth(code_template.untagged(),0));
78         cell size = array_capacity(insns.untagged());
79
80         cell bump = align(size + sizeof(code_block),data_alignment);
81         if(here + bump > seg->end) fatal_error("Out of callback space",0);
82
83         free_heap_block *free_block = (free_heap_block *)here;
84         free_block->make_free(bump);
85         here += bump;
86
87         code_block *stub = (code_block *)free_block;
88         stub->owner = owner;
89         stub->parameters = false_object;
90         stub->relocation = false_object;
91
92         memcpy(stub->entry_point(),insns->data<void>(),size);
93
94         /* Store VM pointer */
95         store_callback_operand(stub,0,(cell)parent);
96
97         cell index;
98
99         if(setup_seh_p())
100         {
101                 store_callback_operand(stub,1);
102                 index = 1;
103         }
104         else
105                 index = 0;
106
107         /* Store VM pointer */
108         store_callback_operand(stub,index + 2,(cell)parent);
109
110         /* On x86, the RET instruction takes an argument which depends on
111         the callback's calling convention */
112         if(return_takes_param_p())
113                 store_callback_operand(stub,index + 3,return_rewind);
114
115         update(stub);
116
117         return stub;
118 }
119
120 struct callback_updater {
121         callback_heap *callbacks;
122
123         explicit callback_updater(callback_heap *callbacks_) : callbacks(callbacks_) {}
124
125         void operator()(code_block *stub)
126         {
127                 callbacks->update(stub);
128         }
129 };
130
131 void callback_heap::update()
132 {
133         callback_updater updater(this);
134         each_callback(updater);
135 }
136
137 void factor_vm::primitive_callback()
138 {
139         cell return_rewind = to_cell(ctx->pop());
140         tagged<word> w(ctx->pop());
141
142         w.untag_check(this);
143
144         void* func = callbacks->add(w.value(),return_rewind)->entry_point();
145         CODE_TO_FUNCTION_POINTER_CALLBACK(this, func);
146         ctx->push(allot_alien(func));
147 }
148
149 }