Exemple #1
0
word *factor_vm::allot_word(cell name_, cell vocab_, cell hashcode_)
{
	data_root<object> vocab(vocab_,this);
	data_root<object> name(name_,this);

	data_root<word> new_word(allot<word>(sizeof(word)),this);

	new_word->hashcode = hashcode_;
	new_word->vocabulary = vocab.value();
	new_word->name = name.value();
	new_word->def = special_objects[OBJ_UNDEFINED];
	new_word->props = false_object;
	new_word->counter = tag_fixnum(0);
	new_word->pic_def = false_object;
	new_word->pic_tail_def = false_object;
	new_word->subprimitive = false_object;
	new_word->profiling = NULL;
	new_word->code = NULL;

	jit_compile_word(new_word.value(),new_word->def,true);
	if(counting_profiler_p)
	{
		code_block *profiling_block = compile_profiling_stub(new_word.value());
		new_word->profiling = profiling_block;
		initialize_code_block(new_word->profiling);
	}

	update_word_entry_point(new_word.untagged());

	return new_word.untagged();
}
Exemple #2
0
// The cache_entries parameter is empty (on cold call site) or has entries
// (on cache miss). Called from assembly with the actual return address.
// Compilation of the inline cache may trigger a GC, which may trigger a
// compaction;
// also, the block containing the return address may now be dead. Use a
// code_root to take care of the details.
// Allocates memory
cell factor_vm::inline_cache_miss(cell return_address_) {
  code_root return_address(return_address_, this);
  bool tail_call_site = tail_call_site_p(return_address.value);

#ifdef PIC_DEBUG
  FACTOR_PRINT("Inline cache miss at "
               << (tail_call_site ? "tail" : "non-tail")
               << " call site 0x" << std::hex << return_address.value
               << std::dec);
  print_callstack();
#endif

  data_root<array> cache_entries(ctx->pop(), this);
  fixnum index = untag_fixnum(ctx->pop());
  data_root<array> methods(ctx->pop(), this);
  data_root<word> generic_word(ctx->pop(), this);
  data_root<object> object(((cell*)ctx->datastack)[-index], this);

  cell pic_size = array_capacity(cache_entries.untagged()) / 2;

  update_pic_transitions(pic_size);

  cell xt = generic_word->entry_point;
  if (pic_size < max_pic_size) {
    cell klass = object_class(object.value());
    cell method = lookup_method(object.value(), methods.value());

    data_root<array> new_cache_entries(
        add_inline_cache_entry(cache_entries.value(), klass, method), this);

    inline_cache_jit jit(generic_word.value(), this);
    jit.emit_inline_cache(index, generic_word.value(), methods.value(),
                          new_cache_entries.value(), tail_call_site);
    code_block* code = jit.to_code_block(CODE_BLOCK_PIC, JIT_FRAME_SIZE);
    initialize_code_block(code);
    xt = code->entry_point();
  }

  // Install the new stub.
  if (return_address.valid) {
    // Since each PIC is only referenced from a single call site,
    // if the old call target was a PIC, we can deallocate it immediately,
    // instead of leaving dead PICs around until the next GC.
    deallocate_inline_cache(return_address.value);
    set_call_target(return_address.value, xt);

#ifdef PIC_DEBUG
    FACTOR_PRINT("Updated " << (tail_call_site ? "tail" : "non-tail")
                 << " call site 0x" << std::hex << return_address.value << std::dec
                 << " with 0x" << std::hex << (cell)xt << std::dec);
    print_callstack();
#endif
  }

  return xt;
}
Exemple #3
0
/* Fix up new words only.
Fast path for compilation units that only define new words. */
void factor_vm::initialize_code_blocks()
{
	std::map<code_block *, cell>::const_iterator iter = code->uninitialized_blocks.begin();
	std::map<code_block *, cell>::const_iterator end = code->uninitialized_blocks.end();

	for(; iter != end; iter++)
		initialize_code_block(iter->first,iter->second);

	code->uninitialized_blocks.clear();
}
Exemple #4
0
// Allocates memory
code_block* factor_vm::jit_compile_quotation(cell owner_, cell quot_,
                                             bool relocating) {
  data_root<object> owner(owner_, this);
  data_root<quotation> quot(quot_, this);

  quotation_jit compiler(owner.value(), true, relocating, this);
  compiler.init_quotation(quot.value());
  compiler.iterate_quotation();

  cell frame_size = compiler.word_stack_frame_size(owner_);

  code_block* compiled = compiler.to_code_block(CODE_BLOCK_UNOPTIMIZED,
                                                frame_size);
  if (relocating)
    initialize_code_block(compiled);

  return compiled;
}
/* Relocate new code blocks completely; updating references to literals,
dlsyms, and words. For all other words in the code heap, we only need
to update references to other words, without worrying about literals
or dlsyms. */
void factor_vm::update_word_references(code_block *compiled)
{
	if(code->uninitialized_p(compiled))
		initialize_code_block(compiled);
	/* update_word_references() is always applied to every block in
	   the code heap. Since it resets all call sites to point to
	   their canonical XT (cold entry point for non-tail calls,
	   standard entry point for tail calls), it means that no PICs
	   are referenced after this is done. So instead of polluting
	   the code heap with dead PICs that will be freed on the next
	   GC, we add them to the free list immediately. */
	else if(compiled->pic_p())
		code->free(compiled);
	else
	{
		update_word_references_relocation_visitor visitor(this);
		compiled->each_instruction_operand(visitor);
		compiled->flush_icache();
	}
}
Exemple #6
0
void factor_vm::initialize_code_block(code_block *compiled)
{
	std::map<code_block *,cell>::iterator iter = code->uninitialized_blocks.find(compiled);
	initialize_code_block(compiled,iter->second);
	code->uninitialized_blocks.erase(iter);
}