]> gitweb.factorcode.org Git - factor.git/blob - vm/callbacks.cpp
VM: change the definition of entry_point in word and quotation from void* to cell
[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   parent->store_external_address(callback_operand(stub, index));
54 }
55
56 void callback_heap::store_callback_operand(code_block* stub, cell index,
57                                            cell value) {
58   callback_operand(stub, index).store_value(value);
59 }
60
61 void callback_heap::update(code_block* stub) {
62   store_callback_operand(stub, setup_seh_p() ? 2 : 1,
63                          callback_entry_point(stub));
64   stub->flush_icache();
65 }
66
67 code_block* callback_heap::add(cell owner, cell return_rewind) {
68   tagged<array> code_template(parent->special_objects[CALLBACK_STUB]);
69   tagged<byte_array> insns(array_nth(code_template.untagged(), 1));
70   cell size = array_capacity(insns.untagged());
71
72   cell bump = align(size + sizeof(code_block), data_alignment);
73   code_block* stub = allocator->allot(bump);
74   if (!stub) {
75     parent->general_error(ERROR_CALLBACK_SPACE_OVERFLOW,
76                           false_object,
77                           false_object);
78   }
79
80   stub->header = bump & ~7;
81   stub->owner = owner;
82   stub->parameters = false_object;
83   stub->relocation = false_object;
84
85   memcpy((void*)stub->entry_point(), insns->data<void>(), size);
86
87   /* Store VM pointer */
88   store_callback_operand(stub, 0, (cell)parent);
89
90   cell index;
91
92   if (setup_seh_p()) {
93     store_callback_operand(stub, 1);
94     index = 1;
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)
115       : callbacks(callbacks) {}
116
117   void operator()(code_block* stub, cell size) {
118     callbacks->update(stub);
119   }
120 };
121
122 void callback_heap::update() {
123   callback_updater updater(this);
124   allocator->iterate(updater);
125 }
126
127 /* Allocates memory (add(), allot_alien())*/
128 void factor_vm::primitive_callback() {
129   cell return_rewind = to_cell(ctx->pop());
130   tagged<word> w(ctx->pop());
131
132   w.untag_check(this);
133
134   cell func = callbacks->add(w.value(), return_rewind)->entry_point();
135   CODE_TO_FUNCTION_POINTER_CALLBACK(this, func);
136   ctx->push(allot_alien((void*)func));
137 }
138
139 void factor_vm::primitive_free_callback() {
140   void* entry_point = alien_offset(ctx->pop());
141   code_block* stub = (code_block*)entry_point - 1;
142   callbacks->allocator->free(stub);
143 }
144
145 /* Allocates memory */
146 void factor_vm::primitive_callback_room() {
147   allocator_room room = callbacks->allocator->as_allocator_room();
148   ctx->push(tag<byte_array>(byte_array_from_value(&room)));
149 }
150
151 }