]> gitweb.factorcode.org Git - factor.git/blob - vm/callbacks.cpp
Put brackets around ipv6 addresses in `inet6 present`
[factor.git] / vm / callbacks.cpp
1 #include "master.hpp"
2
3 namespace factor {
4
5 bool return_takes_param_p() {
6 #if defined(FACTOR_X86) || defined(FACTOR_AMD64)
7   return true;
8 #else
9   return false;
10 #endif
11 }
12
13 callback_heap::callback_heap(cell size, factor_vm* parent) {
14   seg = new segment(size, true);
15   if (!seg)
16     fatal_error("Out of memory in callback_heap constructor", size);
17   allocator = new free_list_allocator<code_block>(size, seg->start);
18   this->parent = parent;
19
20 }
21
22 callback_heap::~callback_heap() {
23   delete allocator;
24   allocator = NULL;
25   delete seg;
26   seg = NULL;
27 }
28
29 instruction_operand callback_heap::callback_operand(code_block* stub,
30                                                     cell index) {
31   tagged<array> code_template(parent->special_objects[CALLBACK_STUB]);
32   tagged<byte_array> relocation_template(
33       array_nth(code_template.untagged(), 0));
34
35   relocation_entry entry(relocation_template->data<relocation_entry>()[index]);
36   return instruction_operand(entry, stub, 0);
37 }
38
39 void callback_heap::store_callback_operand(code_block* stub, cell index,
40                                            cell value) {
41   instruction_operand op = callback_operand(stub, index);
42   op.store_value(value);
43 }
44
45 void callback_heap::update(code_block* stub) {
46   word* w = untag<word>(stub->owner);
47   store_callback_operand(stub, 1, w->entry_point);
48   stub->flush_icache();
49 }
50
51 code_block* callback_heap::add(cell owner, cell return_rewind) {
52   // code_template is a 2-tuple where the first element contains the
53   // relocations and the second a byte array of compiled assembly
54   // code. The code assumes that there are four relocations on x86 and
55   // three on ppc.
56   tagged<array> code_template(parent->special_objects[CALLBACK_STUB]);
57   tagged<byte_array> insns(array_nth(code_template.untagged(), 1));
58   cell size = array_capacity(insns.untagged());
59
60   cell bump = align(size + sizeof(code_block), data_alignment);
61   code_block* stub = allocator->allot(bump);
62   if (!stub) {
63     parent->general_error(ERROR_CALLBACK_SPACE_OVERFLOW,
64                           false_object,
65                           false_object);
66   }
67   stub->header = bump & ~7;
68   stub->owner = owner;
69   stub->parameters = false_object;
70   stub->relocation = false_object;
71
72   memcpy((void*)stub->entry_point(), insns->data<void>(), size);
73
74   // Store VM pointer in two relocations.
75   store_callback_operand(stub, 0, (cell)parent);
76   store_callback_operand(stub, 2, (cell)parent);
77
78   // On x86, the RET instruction takes an argument which depends on
79   // the callback's calling convention
80   if (return_takes_param_p())
81     store_callback_operand(stub, 3, return_rewind);
82
83   update(stub);
84   return stub;
85 }
86
87 // Allocates memory (add(), allot_alien())
88 void factor_vm::primitive_callback() {
89   cell return_rewind = to_cell(ctx->pop());
90   tagged<word> w(ctx->pop());
91   check_tagged(w);
92
93   cell func = callbacks->add(w.value(), return_rewind)->entry_point();
94   CODE_TO_FUNCTION_POINTER_CALLBACK(this, func);
95   ctx->push(allot_alien(func));
96 }
97
98 void factor_vm::primitive_free_callback() {
99   void* entry_point = alien_offset(ctx->pop());
100   code_block* stub = (code_block*)entry_point - 1;
101   callbacks->allocator->free(stub);
102 }
103
104 // Allocates memory
105 void factor_vm::primitive_callback_room() {
106   allocator_room room = callbacks->allocator->as_allocator_room();
107   ctx->push(tag<byte_array>(byte_array_from_value(&room)));
108 }
109
110 }