]> gitweb.factorcode.org Git - factor.git/blobdiff - vm/callbacks.cpp
io.streams.256color: faster by caching styles
[factor.git] / vm / callbacks.cpp
old mode 100755 (executable)
new mode 100644 (file)
index 38479a3..492e7a9
 #include "master.hpp"
 
-namespace factor
-{
-
-callback_heap::callback_heap(cell size, factor_vm *parent_) :
-       seg(new segment(size,true)),
-       here(seg->start),
-       parent(parent_) {}
-
-callback_heap::~callback_heap()
-{
-       delete seg;
-       seg = NULL;
-}
-
-void factor_vm::init_callbacks(cell size)
-{
-       callbacks = new callback_heap(size,this);
-}
-
-bool callback_heap::setup_seh_p()
-{
-#if defined(WINDOWS) && defined(FACTOR_X86)
-       return true;
-#else
-       return false;
-#endif
-}
+namespace factor {
 
-bool callback_heap::return_takes_param_p()
-{
+bool return_takes_param_p() {
 #if defined(FACTOR_X86) || defined(FACTOR_AMD64)
-       return true;
+  return true;
 #else
-       return false;
+  return false;
 #endif
 }
 
-instruction_operand callback_heap::callback_operand(code_block *stub, cell index)
-{
-       tagged<array> code_template(parent->special_objects[CALLBACK_STUB]);
+callback_heap::callback_heap(cell size, factor_vm* parent) {
+  seg = new segment(size, true);
+  if (!seg)
+    fatal_error("Out of memory in callback_heap constructor", size);
+  allocator = new free_list_allocator<code_block>(size, seg->start);
+  this->parent = parent;
 
-       cell rel_class = untag_fixnum(array_nth(code_template.untagged(),3 * index + 1));
-       cell rel_type  = untag_fixnum(array_nth(code_template.untagged(),3 * index + 2));
-       cell offset    = untag_fixnum(array_nth(code_template.untagged(),3 * index + 3));
+}
 
-       relocation_entry rel(
-               (relocation_type)rel_type,
-               (relocation_class)rel_class,
-               offset);
+callback_heap::~callback_heap() {
+  delete allocator;
+  allocator = NULL;
+  delete seg;
+  seg = NULL;
+}
 
-       instruction_operand op(rel,stub,0);
+instruction_operand callback_heap::callback_operand(code_block* stub,
+                                                    cell index) {
+  tagged<array> code_template(parent->special_objects[CALLBACK_STUB]);
+  tagged<byte_array> relocation_template(
+      array_nth(code_template.untagged(), 0));
 
-       return op;
+  relocation_entry entry(relocation_template->data<relocation_entry>()[index]);
+  return instruction_operand(entry, stub, 0);
 }
 
-void callback_heap::store_callback_operand(code_block *stub, cell index)
-{
-       parent->store_external_address(callback_operand(stub,index));
+void callback_heap::store_callback_operand(code_block* stub, cell index,
+                                           cell value) {
+  instruction_operand op = callback_operand(stub, index);
+  op.store_value(value);
 }
 
-void callback_heap::store_callback_operand(code_block *stub, cell index, cell value)
-{
-       callback_operand(stub,index).store_value(value);
+void callback_heap::update(code_block* stub) {
+  word* w = untag<word>(stub->owner);
+  store_callback_operand(stub, 1, w->entry_point);
+  stub->flush_icache();
 }
 
-void callback_heap::update(code_block *stub)
-{
-       store_callback_operand(stub,setup_seh_p() ? 2 : 1,(cell)callback_entry_point(stub));
-       stub->flush_icache();
+code_block* callback_heap::add(cell owner, cell return_rewind) {
+  // code_template is a 2-tuple where the first element contains the
+  // relocations and the second a byte array of compiled assembly
+  // code. The code assumes that there are four relocations on x86 and
+  // three on ppc.
+  tagged<array> code_template(parent->special_objects[CALLBACK_STUB]);
+  tagged<byte_array> insns(array_nth(code_template.untagged(), 1));
+  cell size = array_capacity(insns.untagged());
+
+  cell bump = align(size + sizeof(code_block), data_alignment);
+  code_block* stub = allocator->allot(bump);
+  if (!stub) {
+    parent->general_error(ERROR_CALLBACK_SPACE_OVERFLOW,
+                          false_object,
+                          false_object);
+  }
+  stub->header = bump & ~7;
+  stub->owner = owner;
+  stub->parameters = false_object;
+  stub->relocation = false_object;
+
+  memcpy((void*)stub->entry_point(), insns->data<void>(), size);
+
+  // Store VM pointer in two relocations.
+  store_callback_operand(stub, 0, (cell)parent);
+  store_callback_operand(stub, 2, (cell)parent);
+
+  // On x86, the RET instruction takes an argument which depends on
+  // the callback's calling convention
+  if (return_takes_param_p())
+    store_callback_operand(stub, 3, return_rewind);
+
+  update(stub);
+  return stub;
 }
 
-code_block *callback_heap::add(cell owner, cell return_rewind)
-{
-       tagged<array> code_template(parent->special_objects[CALLBACK_STUB]);
-       tagged<byte_array> insns(array_nth(code_template.untagged(),0));
-       cell size = array_capacity(insns.untagged());
-
-       cell bump = align(size + sizeof(code_block),data_alignment);
-       if(here + bump > seg->end) fatal_error("Out of callback space",0);
-
-       free_heap_block *free_block = (free_heap_block *)here;
-       free_block->make_free(bump);
-       here += bump;
-
-       code_block *stub = (code_block *)free_block;
-       stub->owner = owner;
-       stub->parameters = false_object;
-       stub->relocation = false_object;
+// Allocates memory (add(), allot_alien())
+void factor_vm::primitive_callback() {
+  cell return_rewind = to_cell(ctx->pop());
+  tagged<word> w(ctx->pop());
+  check_tagged(w);
 
-       memcpy(stub->entry_point(),insns->data<void>(),size);
-
-       /* Store VM pointer */
-       store_callback_operand(stub,0,(cell)parent);
-
-       cell index;
-
-       if(setup_seh_p())
-       {
-               store_callback_operand(stub,1);
-               index = 1;
-       }
-       else
-               index = 0;
-
-       /* Store VM pointer */
-       store_callback_operand(stub,index + 2,(cell)parent);
-
-       /* On x86, the RET instruction takes an argument which depends on
-       the callback's calling convention */
-       if(return_takes_param_p())
-               store_callback_operand(stub,index + 3,return_rewind);
-
-       update(stub);
-
-       return stub;
+  cell func = callbacks->add(w.value(), return_rewind)->entry_point();
+  CODE_TO_FUNCTION_POINTER_CALLBACK(this, func);
+  ctx->push(allot_alien(func));
 }
 
-struct callback_updater {
-       callback_heap *callbacks;
-
-       explicit callback_updater(callback_heap *callbacks_) : callbacks(callbacks_) {}
-
-       void operator()(code_block *stub)
-       {
-               callbacks->update(stub);
-       }
-};
-
-void callback_heap::update()
-{
-       callback_updater updater(this);
-       each_callback(updater);
+void factor_vm::primitive_free_callback() {
+  void* entry_point = alien_offset(ctx->pop());
+  code_block* stub = (code_block*)entry_point - 1;
+  callbacks->allocator->free(stub);
 }
 
-void factor_vm::primitive_callback()
-{
-       cell return_rewind = to_cell(ctx->pop());
-       tagged<word> w(ctx->pop());
-
-       w.untag_check(this);
-       ctx->push(allot_alien(callbacks->add(w.value(),return_rewind)->entry_point()));
+// Allocates memory
+void factor_vm::primitive_callback_room() {
+  allocator_room room = callbacks->allocator->as_allocator_room();
+  ctx->push(tag<byte_array>(byte_array_from_value(&room)));
 }
 
 }