]> gitweb.factorcode.org Git - factor.git/blob - vm/callbacks.cpp
70058dad77d807cf1491ac2da7c6461e0237c9bc
[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         tagged<byte_array> relocation_template(array_nth(code_template.untagged(),0));
44
45         relocation_entry entry(relocation_template->data<relocation_entry>()[index]);
46         return instruction_operand(entry,stub,0);
47 }
48
49 void callback_heap::store_callback_operand(code_block *stub, cell index)
50 {
51         parent->store_external_address(callback_operand(stub,index));
52 }
53
54 void callback_heap::store_callback_operand(code_block *stub, cell index, cell value)
55 {
56         callback_operand(stub,index).store_value(value);
57 }
58
59 void callback_heap::update(code_block *stub)
60 {
61         store_callback_operand(stub,setup_seh_p() ? 2 : 1,(cell)callback_entry_point(stub));
62         stub->flush_icache();
63 }
64
65 code_block *callback_heap::add(cell owner, cell return_rewind)
66 {
67         tagged<array> code_template(parent->special_objects[CALLBACK_STUB]);
68         tagged<byte_array> insns(array_nth(code_template.untagged(),1));
69         cell size = array_capacity(insns.untagged());
70
71         cell bump = align(size + sizeof(code_block),data_alignment);
72         if(here + bump > seg->end) fatal_error("Out of callback space",0);
73
74         free_heap_block *free_block = (free_heap_block *)here;
75         free_block->make_free(bump);
76         here += bump;
77
78         code_block *stub = (code_block *)free_block;
79         stub->owner = owner;
80         stub->parameters = false_object;
81         stub->relocation = false_object;
82
83         memcpy(stub->entry_point(),insns->data<void>(),size);
84
85         /* Store VM pointer */
86         store_callback_operand(stub,0,(cell)parent);
87
88         cell index;
89
90         if(setup_seh_p())
91         {
92                 store_callback_operand(stub,1);
93                 index = 1;
94         }
95         else
96                 index = 0;
97
98         /* Store VM pointer */
99         store_callback_operand(stub,index + 2,(cell)parent);
100
101         /* On x86, the RET instruction takes an argument which depends on
102         the callback's calling convention */
103         if(return_takes_param_p())
104                 store_callback_operand(stub,index + 3,return_rewind);
105
106         update(stub);
107
108         return stub;
109 }
110
111 struct callback_updater {
112         callback_heap *callbacks;
113
114         explicit callback_updater(callback_heap *callbacks_) : callbacks(callbacks_) {}
115
116         void operator()(code_block *stub)
117         {
118                 callbacks->update(stub);
119         }
120 };
121
122 void callback_heap::update()
123 {
124         callback_updater updater(this);
125         each_callback(updater);
126 }
127
128 /* Allocates memory */
129 void factor_vm::primitive_callback()
130 {
131         cell return_rewind = to_cell(ctx->pop());
132         tagged<word> w(ctx->pop());
133
134         w.untag_check(this);
135
136         void* func = callbacks->add(w.value(),return_rewind)->entry_point();
137         CODE_TO_FUNCTION_POINTER_CALLBACK(this, func);
138         ctx->push(allot_alien(func));
139 }
140
141 }