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