Example #1
0
void factor_vm::sampler_thread_loop() {
  LARGE_INTEGER counter, new_counter, units_per_second;
  DWORD ok;

  ok = QueryPerformanceFrequency(&units_per_second);
  FACTOR_ASSERT(ok);

  ok = QueryPerformanceCounter(&counter);
  FACTOR_ASSERT(ok);

  counter.QuadPart *= samples_per_second;
  while (atomic::load(&sampling_profiler_p)) {
    SwitchToThread();
    ok = QueryPerformanceCounter(&new_counter);
    FACTOR_ASSERT(ok);
    new_counter.QuadPart *= samples_per_second;
    cell samples = 0;
    while (new_counter.QuadPart - counter.QuadPart >
           units_per_second.QuadPart) {
      ++samples;
      counter.QuadPart += units_per_second.QuadPart;
    }
    if (samples == 0)
      continue;

    cell pc = get_thread_pc(thread);
    enqueue_samples(samples, pc, false);
  }
}
Example #2
0
 void set_stack_frame_size(cell frame_size) {
   FACTOR_ASSERT(size() < 0xFFFFFF);
   FACTOR_ASSERT(!free_p());
   FACTOR_ASSERT(frame_size % 16 == 0);
   FACTOR_ASSERT(frame_size <= 0xFF0);
   header = (header & 0xFFFFFF) | (frame_size << 20);
 }
Example #3
0
inline void factor_vm::set_array_nth(array* array, cell slot, cell value) {
  FACTOR_ASSERT(slot < array_capacity(array));
  FACTOR_ASSERT(array->type() == ARRAY_TYPE);
  cell* slot_ptr = &array->data()[slot];
  *slot_ptr = value;
  write_barrier(slot_ptr);
}
Example #4
0
code_block* code_heap::code_block_for_address(cell address) {
  std::set<cell>::const_iterator blocki = all_blocks.upper_bound(address);
  FACTOR_ASSERT(blocki != all_blocks.begin());
  --blocki;
  code_block* found_block = (code_block*)*blocki;
  FACTOR_ASSERT(found_block->entry_point() <=
                address /* XXX this isn't valid during fixup. should store the
                               size in the map
                              && address - found_block->entry_point() <
                                 found_block->size()*/);
  return found_block;
}
Example #5
0
cell get_thread_pc(THREADHANDLE th) {
  DWORD suscount = SuspendThread(th);
  FACTOR_ASSERT(suscount == 0);

  CONTEXT context;
  memset((void*)&context, 0, sizeof(CONTEXT));
  context.ContextFlags = CONTEXT_CONTROL;
  BOOL context_ok = GetThreadContext(th, &context);
  FACTOR_ASSERT(context_ok);

  suscount = ResumeThread(th);
  FACTOR_ASSERT(suscount == 1);
  return context.EIP;
}
Example #6
0
void factor_vm::dispatch_non_resumable_signal(cell* sp, cell* pc,
                                              cell handler,
                                              cell limit) {

  // Fault came from the VM or foreign code. We don't try to fix the
  // call stack from *sp and instead use the last saved "good value"
  // which we get from ctx->callstack_top. Then launch the handler
  // without going through the resumable subprimitive.
  cell frame_top = ctx->callstack_top;
  cell seg_start = ctx->callstack_seg->start;

  if (frame_top < seg_start) {
    // The saved callstack pointer is outside the callstack
    // segment. That means that we need to carefully cut off one frame
    // first which hopefully should put the pointer within the
    // callstack's bounds.
    code_block *block = code->code_block_for_address(*pc);
    cell frame_size = block->stack_frame_size_for_address(*pc);
    frame_top += frame_size;
  }

  // Cut the callstack down to the shallowest Factor stack
  // frame that leaves room for the signal handler to do its thing,
  // and launch the handler without going through the resumable
  // subprimitive.
  FACTOR_ASSERT(seg_start <= frame_top);
  while (frame_top < ctx->callstack_bottom && frame_top < limit) {
    frame_top = code->frame_predecessor(frame_top);
  }
  ctx->callstack_top = frame_top;
  *sp = frame_top;
  *pc = handler;
}
Example #7
0
void code_heap::free(code_block* compiled) {
  FACTOR_ASSERT(!uninitialized_p(compiled));
  points_to_nursery.erase(compiled);
  points_to_aging.erase(compiled);
  all_blocks.erase((cell)compiled);
  allocator->free(compiled);
}
Example #8
0
inline void factor_vm::iterate_callstack(context* ctx, Iterator& iterator,
                                         Fixup& fixup) {
  if (ctx->callstack_top == ctx->callstack_bottom)
    return;

  char* frame_top = (char*)ctx->callstack_top;

  while (frame_top < (char*)ctx->callstack_bottom) {
    void* addr = frame_return_address((void*)frame_top);
    FACTOR_ASSERT(addr != 0);
    void* fixed_addr = Fixup::translated_code_block_map
                           ? (void*)fixup.translate_code((code_block*)addr)
                           : addr;

    code_block* owner = code->code_block_for_address((cell)fixed_addr);
    code_block* fixed_owner =
        Fixup::translated_code_block_map ? owner : fixup.translate_code(owner);

    cell frame_size =
        fixed_owner->stack_frame_size_for_address((cell)fixed_addr);

    void* fixed_addr_for_iter =
        Fixup::translated_code_block_map ? fixed_addr : addr;

    iterator(frame_top, frame_size, owner, fixed_addr_for_iter);
    frame_top += frame_size;
  }
}
Example #9
0
// Compile code in boot image so that we can execute the startup quotation
// Allocates memory
void factor_vm::prepare_boot_image() {
  std::cout << "*** Stage 2 early init... " << std::flush;

  // Compile all words.
  data_root<array> words(instances(WORD_TYPE), this);

  cell n_words = array_capacity(words.untagged());
  for (cell i = 0; i < n_words; i++) {
    data_root<word> word(array_nth(words.untagged(), i), this);

    FACTOR_ASSERT(!word->entry_point);
    jit_compile_word(word.value(), word->def, false);
  }
  update_code_heap_words(true);

  // Initialize all quotations
  data_root<array> quotations(instances(QUOTATION_TYPE), this);

  cell n_quots = array_capacity(quotations.untagged());
  for (cell i = 0; i < n_quots; i++) {
    data_root<quotation> quot(array_nth(quotations.untagged(), i), this);

    if (!quot->entry_point)
      quot->entry_point = lazy_jit_compile_entry_point();
  }

  special_objects[OBJ_STAGE2] = special_objects[OBJ_CANONICAL_TRUE];

  std::cout << "done" << std::endl;
}
Example #10
0
void *factor_vm::frame_predecessor(void *frame_top)
{
	void *addr = frame_return_address((void*)frame_top);
	FACTOR_ASSERT(addr != 0);
	code_block *owner = code->code_block_for_address((cell)addr);
	cell frame_size = owner->stack_frame_size_for_address((cell)addr);
	return (void*)((char*)frame_top + frame_size);
}
Example #11
0
cell code_heap::frame_predecessor(cell frame_top) {
  cell addr = *(cell*)frame_top;
  FACTOR_ASSERT(seg->in_segment_p(addr));
  //FACTOR_ASSERT(addr != 0);
  code_block* owner = code_block_for_address(addr);
  cell frame_size = owner->stack_frame_size_for_address(addr);
  return frame_top + frame_size;
}
Example #12
0
void factor_vm::lock_console() {
  FACTOR_ASSERT(stdin_thread_initialized_p);
  /* Lock the stdin_mutex and send the stdin_loop thread a signal to interrupt
     any read() it has in progress. When the stdin loop iterates again, it will
     try to lock the same mutex and wait until unlock_console() is called. */
  pthread_mutex_lock(&stdin_mutex);
  pthread_kill(stdin_thread, SIGUSR2);
}
Example #13
0
inline static THREADHANDLE thread_id() {
  DWORD id = GetCurrentThreadId();
  HANDLE threadHandle = OpenThread(
      THREAD_GET_CONTEXT | THREAD_SET_CONTEXT | THREAD_SUSPEND_RESUME, FALSE,
      id);
  FACTOR_ASSERT(threadHandle != NULL);
  return threadHandle;
}
Example #14
0
void factor_vm::open_console() {
  FACTOR_ASSERT(!stdin_thread_initialized_p);
  safe_pipe(&control_read, &control_write);
  safe_pipe(&size_read, &size_write);
  safe_pipe(&stdin_read, &stdin_write);
  stdin_thread = start_thread(stdin_loop, NULL);
  stdin_thread_initialized_p = true;
  pthread_mutex_init(&stdin_mutex, NULL);
}
Example #15
0
void factor_vm::delete_contexts() {
  FACTOR_ASSERT(!ctx);
  std::list<context*>::const_iterator iter = unused_contexts.begin();
  std::list<context*>::const_iterator end = unused_contexts.end();
  while (iter != end) {
    delete *iter;
    iter++;
  }
}
Example #16
0
  void operator()(code_block* compiled, cell size) {
    objects.push_back(compiled->owner);
    objects.push_back(compiled->parameters);
    objects.push_back(compiled->relocation);

    objects.push_back(tag_fixnum(compiled->type()));
    objects.push_back(tag_fixnum(compiled->size()));

    /* Note: the entry point is always a multiple of the heap
       alignment (16 bytes). We cannot allocate while iterating
       through the code heap, so it is not possible to call
       from_unsigned_cell() here. It is OK, however, to add it as
       if it were a fixnum, and have library code shift it to the
       left by 4. */
    cell entry_point = compiled->entry_point();
    FACTOR_ASSERT((entry_point & (data_alignment - 1)) == 0);
    FACTOR_ASSERT((entry_point & TAG_MASK) == FIXNUM_TYPE);
    objects.push_back(entry_point);
  }
Example #17
0
// Allocates memory
cell factor_vm::lazy_jit_compile(cell quot_) {
  data_root<quotation> quot(quot_, this);

  FACTOR_ASSERT(!quotation_compiled_p(quot.untagged()));

  code_block* compiled =
      jit_compile_quotation(quot.value(), quot.value(), true);
  quot.untagged()->entry_point = compiled->entry_point();

  return quot.value();
}
Example #18
0
  /*
	frame top -> [return address]
	             [spill area]
	             ...
	             [entry_point]
	             [size]
	*/
  void operator()(void* frame_top, cell frame_size, code_block* owner,
                  void* addr) {
    cell return_address = owner->offset(addr);

    code_block* compiled =
        Fixup::translated_code_block_map ? owner
                                         : visitor->fixup.translate_code(owner);
    gc_info* info = compiled->block_gc_info();

    FACTOR_ASSERT(return_address < compiled->size());
    cell callsite = info->return_address_index(return_address);
    if (callsite == (cell)-1)
      return;

#ifdef DEBUG_GC_MAPS
    std::cout << "call frame code block " << compiled << " with offset "
              << return_address << std::endl;
#endif
    cell* stack_pointer = (cell*)frame_top;
    uint8_t* bitmap = info->gc_info_bitmap();

    /* Subtract old value of base pointer from every derived pointer. */
    for (cell spill_slot = 0; spill_slot < info->derived_root_count;
         spill_slot++) {
      uint32_t base_pointer = info->lookup_base_pointer(callsite, spill_slot);
      if (base_pointer != (uint32_t)-1) {
#ifdef DEBUG_GC_MAPS
        std::cout << "visiting derived root " << spill_slot
                  << " with base pointer " << base_pointer << std::endl;
#endif
        stack_pointer[spill_slot] -= stack_pointer[base_pointer];
      }
    }

    /* Update all GC roots, including base pointers. */
    cell callsite_gc_roots = info->callsite_gc_roots(callsite);

    for (cell spill_slot = 0; spill_slot < info->gc_root_count; spill_slot++) {
      if (bitmap_p(bitmap, callsite_gc_roots + spill_slot)) {
#ifdef DEBUG_GC_MAPS
        std::cout << "visiting GC root " << spill_slot << std::endl;
#endif
        visitor->visit_handle(stack_pointer + spill_slot);
      }
    }

    /* Add the base pointers to obtain new derived pointer values. */
    for (cell spill_slot = 0; spill_slot < info->derived_root_count;
         spill_slot++) {
      uint32_t base_pointer = info->lookup_base_pointer(callsite, spill_slot);
      if (base_pointer != (uint32_t)-1)
        stack_pointer[spill_slot] += stack_pointer[base_pointer];
    }
  }
Example #19
0
File: gc.cpp Project: Renha/factor
    void operator()(void *frame_top, cell frame_size, code_block *owner, void *addr)
    {
        cell return_address = owner->offset(addr);

        gc_info *info = owner->block_gc_info();

        FACTOR_ASSERT(return_address < owner->size());
        cell index = info->return_address_index(return_address);
        if(index != (cell)-1)
            ctx->scrub_stacks(info,index);
    }
Example #20
0
cell factor_vm::code_block_owner(code_block *compiled)
{
	tagged<object> owner(compiled->owner);

	/* Cold generic word call sites point to quotations that call the
	inline-cache-miss and inline-cache-miss-tail primitives. */
	if(owner.type_p(QUOTATION_TYPE))
	{
		tagged<quotation> quot(owner.as<quotation>());
		tagged<array> elements(quot->array);
#ifdef FACTOR_DEBUG
		FACTOR_ASSERT(array_capacity(elements.untagged()) == 5);
		FACTOR_ASSERT(array_nth(elements.untagged(),4) == special_objects[PIC_MISS_WORD]
			|| array_nth(elements.untagged(),4) == special_objects[PIC_MISS_TAIL_WORD]);
#endif
		tagged<wrapper> word_wrapper(array_nth(elements.untagged(),0));
		return word_wrapper->object;
	}
	else
		return compiled->owner;
}
Example #21
0
cell object_start_map::find_object_containing_card(cell card_index) {
  if (card_index == 0)
    return start;
  card_index--;

  while (object_start_offsets[card_index] == card_starts_inside_object) {
    // First card should start with an object
    FACTOR_ASSERT(card_index > 0);
    card_index--;
  }
  return start + card_index * card_size + object_start_offsets[card_index];
}
Example #22
0
File: jit.cpp Project: Bigot/factor
/* Allocates memory */
jit::jit(code_block_type type, cell owner, factor_vm* vm)
    : type(type),
      owner(owner, vm),
      code(vm),
      relocation(vm),
      parameters(vm),
      literals(vm),
      computing_offset_p(false),
      position(0),
      offset(0),
      parent(vm) {
  fixnum old_count = atomic::fetch_add(&parent->current_jit_count, 1);
  FACTOR_ASSERT(old_count >= 0);
  (void)old_count;
}
Example #23
0
void factor_vm::dispatch_resumable_signal(cell* sp, cell* pc, cell handler) {

  // Fault came from Factor, and we've got a good callstack. Route the
  // signal handler through the resumable signal handler
  // subprimitive.

  cell offset = *sp % 16;

  signal_handler_addr = handler;

  // True stack frames are always 16-byte aligned. Leaf procedures
  // that don't create a stack frame will be out of alignment by
  // sizeof(cell) bytes.
  // On architectures with a link register we would have to check for
  // leafness by matching the PC to a word. We should also use
  // FRAME_RETURN_ADDRESS instead of assuming the stack pointer is the
  // right place to put the resume address.
  cell index = 0;
  cell delta = 0;
  if (offset == 0) {
    delta = sizeof(cell);
    index = SIGNAL_HANDLER_WORD;
  } else if (offset == 16 - sizeof(cell)) {
    // Make a fake frame for the leaf procedure
    FACTOR_ASSERT(code->code_block_for_address(*pc) != NULL);
    delta = LEAF_FRAME_SIZE;
    index = LEAF_SIGNAL_HANDLER_WORD;
  } else {
    FACTOR_ASSERT(false);
  }
  cell new_sp = *sp - delta;
  *sp = new_sp;
  *(cell*)new_sp = *pc;

  *pc = untag<word>(special_objects[index])->entry_point;
}
Example #24
0
static void call_fault_handler(mach_port_t thread, exception_type_t exception,
                               exception_data_type_t code,
                               MACH_EXC_STATE_TYPE* exc_state,
                               MACH_THREAD_STATE_TYPE* thread_state,
                               MACH_FLOAT_STATE_TYPE* float_state) {
  /* Look up the VM instance involved */
  THREADHANDLE thread_id = pthread_from_mach_thread_np(thread);
  FACTOR_ASSERT(thread_id);
  std::map<THREADHANDLE, factor_vm*>::const_iterator vm =
      thread_vms.find(thread_id);

  /* Handle the exception */
  if (vm != thread_vms.end())
    vm->second->call_fault_handler(exception, code, exc_state, thread_state,
                                   float_state);
}
Example #25
0
void safepoint_state::handle_safepoint(factor_vm* parent, cell pc) volatile {
  parent->code->set_safepoint_guard(false);
  parent->faulting_p = false;

  if (atomic::load(&fep_p)) {
    if (atomic::load(&parent->sampling_profiler_p))
      parent->end_sampling_profiler();
    std::cout << "Interrupted\n";
    parent->factorbug();
    atomic::store(&fep_p, false);
  } else if (atomic::load(&parent->sampling_profiler_p)) {
    FACTOR_ASSERT(parent->code->seg->in_segment_p(pc));
    code_block* block = parent->code->code_block_for_address(pc);
    bool prolog_p = block->entry_point() == pc;

    parent->record_sample(prolog_p);
  }
}
Example #26
0
// Allocates memory
inline object* factor_vm::allot_object(cell type, cell size) {
  FACTOR_ASSERT(!current_gc);

  bump_allocator *nursery = data->nursery;

  // If the object is bigger than the nursery, allocate it in tenured space
  if (size >= nursery->size)
    return allot_large_object(type, size);

  // If the object is smaller than the nursery, allocate it in the nursery,
  // after a GC if needed
  if (nursery->here + size > nursery->end)
    primitive_minor_gc();

  object* obj = nursery->allot(size);
  obj->initialize(type);
  return obj;
}
Example #27
0
static BOOL WINAPI ctrl_handler(DWORD dwCtrlType) {
  switch (dwCtrlType) {
    case CTRL_C_EVENT: {
      // The CtrlHandler runs in its own thread without stopping the main
      // thread. Since in practice nobody uses the multi-VM stuff yet, we just
      // grab the first VM we can get. This will not be a good idea when we
      // actually support native threads.
      FACTOR_ASSERT(thread_vms.size() == 1);
      factor_vm* vm = thread_vms.begin()->second;
      vm->enqueue_fep();

      // Before leaving the ctrl_handler, try and wake up the main thread.
      wake_up_thread(factor::boot_thread);
      return TRUE;
    }
    default:
      return FALSE;
  }
}
Example #28
0
/* Allocates memory */
inline object* factor_vm::allot_object(cell type, cell size) {
  FACTOR_ASSERT(!current_gc);

  bump_allocator *nursery = data->nursery;
  /* If the object is smaller than the nursery, allocate it in the nursery,
     after a GC if needed */
  if (nursery->size > size) {
    /* If there is insufficient room, collect the nursery */
    if (nursery->here + size > nursery->end)
      primitive_minor_gc();

    object* obj = nursery->allot(size);

    obj->initialize(type);
    return obj;
  } /* If the object is bigger than the nursery, allocate it in
       tenured space */
  else
    return allot_large_object(type, size);
}
Example #29
0
size_t raw_fread(void* ptr, size_t size, size_t nitems, FILE* stream) {
  FACTOR_ASSERT(nitems > 0);
  size_t items_read = 0;

  do {
    size_t ret = fread((void*)((int*)ptr + items_read * size), size,
                       nitems - items_read, stream);
    if (ret == 0) {
      if (feof(stream)) {
        break;
      }
      else if (errno != EINTR) {
        return 0;
      }
    }
    items_read += ret;
  } while (items_read != nitems);

  return items_read;
}
Example #30
0
/* Modify a suspended thread's thread_state so that when the thread resumes
   executing, the call frame of the current C primitive (if any) is rewound, and
   the appropriate Factor error is thrown from the top-most Factor frame. */
void factor_vm::call_fault_handler(exception_type_t exception,
                                   exception_data_type_t code,
                                   MACH_EXC_STATE_TYPE* exc_state,
                                   MACH_THREAD_STATE_TYPE* thread_state,
                                   MACH_FLOAT_STATE_TYPE* float_state) {
  cell handler = 0;

  if (exception == EXC_BAD_ACCESS) {
    signal_fault_addr = MACH_EXC_STATE_FAULT(exc_state);
    signal_fault_pc = (cell)MACH_PROGRAM_COUNTER(thread_state);
    verify_memory_protection_error(signal_fault_addr);
    handler = (cell)factor::memory_signal_handler_impl;
  } else if (exception == EXC_ARITHMETIC && code != MACH_EXC_INTEGER_DIV) {
    signal_fpu_status = fpu_status(mach_fpu_status(float_state));
    mach_clear_fpu_status(float_state);
    handler = (cell)factor::fp_signal_handler_impl;
  } else {
    switch (exception) {
      case EXC_ARITHMETIC:
        signal_number = SIGFPE;
        break;
      case EXC_BAD_INSTRUCTION:
        signal_number = SIGILL;
        break;
      default:
        signal_number = SIGABRT;
        break;
    }

    handler = (cell)factor::synchronous_signal_handler_impl;
  }

  FACTOR_ASSERT(handler != 0);

  dispatch_signal_handler((cell*)&MACH_STACK_POINTER(thread_state),
                          (cell*)&MACH_PROGRAM_COUNTER(thread_state),
                          (cell)handler);
}