Exemple #1
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;
}
Exemple #2
0
// Allocates memory
void growable_array::append(array* elts_) {
  factor_vm* parent = elements.parent;
  data_root<array> elts(elts_, parent);
  cell capacity = array_capacity(elts.untagged());
  if (count + capacity > array_capacity(elements.untagged())) {
    reallot_array(2 * (count + capacity));
  }

  for (cell index = 0; index < capacity; index++)
    parent->set_array_nth(elements.untagged(), count++,
                          array_nth(elts.untagged(), index));
}
Exemple #3
0
/* Allocates memory */
void growable_byte_array::append_byte_array(cell byte_array_) {
  data_root<byte_array> byte_array(byte_array_, elements.parent);

  cell len = array_capacity(byte_array.untagged());
  cell new_size = count + len;
  factor_vm* parent = elements.parent;
  if (new_size >= array_capacity(elements.untagged()))
    elements = parent->reallot_array(elements.untagged(), new_size * 2);

  memcpy(&elements->data<uint8_t>()[count], byte_array->data<uint8_t>(), len);

  count += len;
}
Exemple #4
0
void growable_byte_array::append_byte_array(cell byte_array_)
{
	gc_root<byte_array> byte_array(byte_array_,elements.myvm);

	cell len = array_capacity(byte_array.untagged());
	cell new_size = count + len;
	factorvm *myvm = elements.myvm;
	if(new_size >= array_capacity(elements.untagged()))
		elements = myvm->reallot_array(elements.untagged(),new_size * 2);

	memcpy(&elements->data<u8>()[count],byte_array->data<u8>(),len);

	count += len;
}
/* Might GC */
code_block *factor_vm::add_code_block(code_block_type type, cell code_, cell labels_,
	cell owner_, cell relocation_, cell parameters_, cell literals_,
	cell frame_size_untagged)
{
	data_root<byte_array> code(code_,this);
	data_root<object> labels(labels_,this);
	data_root<object> owner(owner_,this);
	data_root<byte_array> relocation(relocation_,this);
	data_root<array> parameters(parameters_,this);
	data_root<array> literals(literals_,this);

	cell code_length = array_capacity(code.untagged());
	code_block *compiled = allot_code_block(code_length,type);

	compiled->owner = owner.value();

	/* slight space optimization */
	if(relocation.type() == BYTE_ARRAY_TYPE && array_capacity(relocation.untagged()) == 0)
		compiled->relocation = false_object;
	else
		compiled->relocation = relocation.value();

	if(parameters.type() == ARRAY_TYPE && array_capacity(parameters.untagged()) == 0)
		compiled->parameters = false_object;
	else
		compiled->parameters = parameters.value();

	/* code */
	memcpy(compiled + 1,code.untagged() + 1,code_length);

	/* fixup labels */
	if(to_boolean(labels.value()))
		fixup_labels(labels.as<array>().untagged(),compiled);

	compiled->set_stack_frame_size(frame_size_untagged);

	/* Once we are ready, fill in literal and word references in this code
	block's instruction operands. In most cases this is done right after this
	method returns, except when compiling words with the non-optimizing
	compiler at the beginning of bootstrap */
	this->code->uninitialized_blocks.insert(std::make_pair(compiled,literals.value()));
	this->code->all_blocks.insert((cell)compiled);

	/* next time we do a minor GC, we have to trace this code block, since
	the fields of the code_block struct might point into nursery or aging */
	this->code->write_barrier(compiled);

	return compiled;
}
Exemple #6
0
/* Allocates memory */
void factor_vm::set_profiling(bool profiling)
{
	if(profiling == profiling_p)
		return;

	profiling_p = profiling;

	/* Push everything to tenured space so that we can heap scan
	and allocate profiling blocks if necessary */
	gc();

	gc_root<array> words(find_all_words(),this);

	cell i;
	cell length = array_capacity(words.untagged());
	for(i = 0; i < length; i++)
	{
		tagged<word> word(array_nth(words.untagged(),i));
		if(profiling)
			word->counter = tag_fixnum(0);
		update_word_xt(word.value());
	}

	update_code_heap_words();
}
	void VolumePimWizardPage::SetPimValidator ()
	{
		wxTextValidator validator (wxFILTER_INCLUDE_CHAR_LIST);  // wxFILTER_NUMERIC does not exclude - . , etc.
		const wxChar *valArr[] = { L"0", L"1", L"2", L"3", L"4", L"5", L"6", L"7", L"8", L"9" };
		validator.SetIncludes (wxArrayString (array_capacity (valArr), (const wxChar **) &valArr));
		VolumePimTextCtrl->SetValidator (validator);
	}
Exemple #8
0
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;
}
Exemple #9
0
void set_profiling(bool profiling)
{
	if(profiling == profiling_p)
		return;

	profiling_p = profiling;

	/* Push everything to tenured space so that we can heap scan
	and allocate profiling blocks if necessary */
	gc();

	CELL words = find_all_words();

	REGISTER_ROOT(words);

	CELL i;
	CELL length = array_capacity(untag_object(words));
	for(i = 0; i < length; i++)
	{
		F_WORD *word = untag_word(array_nth(untag_array(words),i));
		if(profiling)
			word->counter = tag_fixnum(0);
		update_word_xt(word);
	}

	UNREGISTER_ROOT(words);

	/* Update XTs in code heap */
	iterate_code_heap(relocate_code_block);
}
Exemple #10
0
void primitive_fwrite(void)
{
    FILE *file = unbox_alien();
    F_BYTE_ARRAY *text = untag_byte_array(dpop());
    F_FIXNUM length = array_capacity(text);
    char *string = (char *)(text + 1);

    if(length == 0)
        return;

    for(;;)
    {
        size_t written = fwrite(string,1,length,file);
        if(written == length)
            break;
        else
        {
            if(feof(file))
                break;
            else
                io_error();

            /* Still here? EINTR */
            length -= written;
            string += written;
        }
    }
}
Exemple #11
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);
}
Exemple #12
0
/* The number of cells from the start of the object which should be scanned by
the GC. Some types have a binary payload at the end (string, word, DLL) which
we ignore. */
cell factor_vm::binary_payload_start(object *pointer)
{
    switch(pointer->h.hi_tag())
    {
    /* these objects do not refer to other objects at all */
    case FLOAT_TYPE:
    case BYTE_ARRAY_TYPE:
    case BIGNUM_TYPE:
    case CALLSTACK_TYPE:
        return 0;
    /* these objects have some binary data at the end */
    case WORD_TYPE:
        return sizeof(word) - sizeof(cell) * 3;
    case ALIEN_TYPE:
        return sizeof(cell) * 3;
    case DLL_TYPE:
        return sizeof(cell) * 2;
    case QUOTATION_TYPE:
        return sizeof(quotation) - sizeof(cell) * 2;
    case STRING_TYPE:
        return sizeof(string);
    /* everything else consists entirely of pointers */
    case ARRAY_TYPE:
        return array_size<array>(array_capacity((array*)pointer));
    case TUPLE_TYPE:
        return tuple_size(untag<tuple_layout>(((tuple *)pointer)->layout));
    case WRAPPER_TYPE:
        return sizeof(wrapper);
    default:
        critical_error("Invalid header",(cell)pointer);
        return 0; /* can't happen */
    }
}
Exemple #13
0
cell factor_vm::lookup_tuple_method(cell obj, cell methods)
{
	tuple_layout *layout = untag<tuple_layout>(untag<tuple>(obj)->layout);

	array *echelons = untag<array>(methods);

	fixnum echelon = untag_fixnum(layout->echelon);
	fixnum max_echelon = array_capacity(echelons) - 1;
	if(echelon > max_echelon) echelon = max_echelon;
       
	while(echelon >= 0)
	{
		cell echelon_methods = array_nth(echelons,echelon);

		if(tagged<object>(echelon_methods).type_p(WORD_TYPE))
			return echelon_methods;
		else if(echelon_methods != F)
		{
			cell klass = nth_superclass(layout,echelon);
			cell hashcode = untag_fixnum(nth_hashcode(layout,echelon));
			cell result = search_lookup_hash(echelon_methods,klass,hashcode);
			if(result != F)
				return result;
		}

		echelon--;
	}

	critical_error("Cannot find tuple method",methods);
	return F;
}
Exemple #14
0
/* Do some initialization that we do once only */
void do_stage1_init(void)
{
	print_string("*** Stage 2 early init... ");
	fflush(stdout);

	CELL words = find_all_words();

	REGISTER_ROOT(words);

	CELL i;
	CELL length = array_capacity(untag_object(words));
	for(i = 0; i < length; i++)
	{
		F_WORD *word = untag_word(array_nth(untag_array(words),i));
		REGISTER_UNTAGGED(word);
		default_word_code(word,false);
		UNREGISTER_UNTAGGED(word);
		update_word_xt(word);
	}

	UNREGISTER_ROOT(words);

	iterate_code_heap(relocate_code_block);

	userenv[STAGE2_ENV] = T;

	print_string("done\n");
	fflush(stdout);
}
Exemple #15
0
/* Allocates memory */
void jit::emit(cell code_template_)
{
	gc_root<array> code_template(code_template_,parent_vm);

	emit_relocation(code_template.value());

	gc_root<byte_array> insns(array_nth(code_template.untagged(),0),parent_vm);

	if(computing_offset_p)
	{
		cell size = array_capacity(insns.untagged());

		if(offset == 0)
		{
			position--;
			computing_offset_p = false;
		}
		else if(offset < size)
		{
			position++;
			computing_offset_p = false;
		}
		else
			offset -= size;
	}

	code.append_byte_array(insns.value());
}
Exemple #16
0
inline cell array_nth(array *array, cell slot)
{
#ifdef FACTOR_DEBUG
	assert(slot < array_capacity(array));
	assert(array->h.hi_tag() == ARRAY_TYPE);
#endif
	return array->data()[slot];
}
Exemple #17
0
int edb_array_capacity(obj_handle *h, u32 *capacity) {
  LOG_HERE;
  int err = 0;
  u32 root;
  CHECK(obj_read(h, &root));
  *capacity = array_capacity(h->db, root);
  err: return err;
}
Exemple #18
0
// Allocates memory
void growable_array::add(cell elt_) {
  factor_vm* parent = elements.parent;
  data_root<object> elt(elt_, parent);
  if (count == array_capacity(elements.untagged()))
    elements = parent->reallot_array(elements.untagged(), count * 2);

  parent->set_array_nth(elements.untagged(), count++, elt.value());
}
Exemple #19
0
cell factor_vm::search_lookup_hash(cell table, cell klass, cell hashcode)
{
	array *buckets = untag<array>(table);
	cell bucket = array_nth(buckets,hashcode & (array_capacity(buckets) - 1));
	if(TAG(bucket) == ARRAY_TYPE)
		return search_lookup_alist(bucket,klass);
	else
		return bucket;
}
Exemple #20
0
cell factor_vm::search_lookup_hash(cell table, cell klass, cell hashcode)
{
	array *buckets = untag<array>(table);
	cell bucket = array_nth(buckets,hashcode & (array_capacity(buckets) - 1));
	if(tagged<object>(bucket).type_p(WORD_TYPE) || bucket == F)
		return bucket;
	else
		return search_lookup_alist(bucket,klass);
}
Exemple #21
0
void factor_vm::primitive_modify_code_heap()
{
	bool reset_inline_caches = to_boolean(ctx->pop());
	bool update_existing_words = to_boolean(ctx->pop());
	data_root<array> alist(ctx->pop(),this);

	cell count = array_capacity(alist.untagged());

	if(count == 0)
		return;

	for(cell i = 0; i < count; i++)
	{
		data_root<array> pair(array_nth(alist.untagged(),i),this);

		data_root<word> word(array_nth(pair.untagged(),0),this);
		data_root<object> data(array_nth(pair.untagged(),1),this);

		switch(data.type())
		{
		case QUOTATION_TYPE:
			jit_compile_word(word.value(),data.value(),false);
			break;
		case ARRAY_TYPE:
			{
				array *compiled_data = data.as<array>().untagged();
				cell parameters = array_nth(compiled_data,0);
				cell literals = array_nth(compiled_data,1);
				cell relocation = array_nth(compiled_data,2);
				cell labels = array_nth(compiled_data,3);
				cell code = array_nth(compiled_data,4);

				code_block *compiled = add_code_block(
					code_block_optimized,
					code,
					labels,
					word.value(),
					relocation,
					parameters,
					literals);

				word->code = compiled;
			}
			break;
		default:
			critical_error("Expected a quotation or an array",data.value());
			break;
		}

		update_word_entry_point(word.untagged());
	}

	if(update_existing_words)
		update_code_heap_words(reset_inline_caches);
	else
		initialize_code_blocks();
}
Exemple #22
0
/* true if there are no non-safepoint words in the quoation... */
bool quotation_jit::no_non_safepoint_words_p() {
  cell length = array_capacity(elements.untagged());
  for (cell i = 0; i < length; i++) {
    cell obj = array_nth(elements.untagged(), i);
    if (TAG(obj) == WORD_TYPE && !word_safepoint_p(obj))
      return false;
  }
  return true;
}
Exemple #23
0
// Figure out what kind of type check the PIC needs based on the methods
// it contains
static cell determine_inline_cache_type(array* cache_entries) {
  for (cell i = 0; i < array_capacity(cache_entries); i += 2) {
    // Is it a tuple layout?
    if (TAG(array_nth(cache_entries, i)) == ARRAY_TYPE) {
      return PIC_TUPLE;
    }
  }
  return PIC_TAG;
}
Exemple #24
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 #25
0
//arrays.hpp
inline void factorvm::set_array_nth(array *array, cell slot, cell value)
{
#ifdef FACTOR_DEBUG
	assert(slot < array_capacity(array));
	assert(array->h.hi_tag() == ARRAY_TYPE);
	check_tagged_pointer(value);
#endif
	array->data()[slot] = value;
	write_barrier(array);
}
Exemple #26
0
/* classes.tuple uses this to reshape tuples; tools.deploy.shaker uses this
   to coalesce equal but distinct quotations and wrappers. */
void factor_vm::primitive_become()
{
	array *new_objects = untag_check<array>(ctx->pop());
	array *old_objects = untag_check<array>(ctx->pop());

	cell capacity = array_capacity(new_objects);
	if(capacity != array_capacity(old_objects))
		critical_error("bad parameters to become",0);

	/* Build the forwarding map */
	std::map<object *,object *> become_map;

	for(cell i = 0; i < capacity; i++)
	{
		tagged<object> old_obj(array_nth(old_objects,i));
		tagged<object> new_obj(array_nth(new_objects,i));

		if(old_obj != new_obj)
			become_map[old_obj.untagged()] = new_obj.untagged();
	}

	/* Update all references to old objects to point to new objects */
	{
		slot_visitor<slot_become_fixup> workhorse(this,slot_become_fixup(&become_map));
		workhorse.visit_roots();
		workhorse.visit_contexts();

		object_become_visitor object_visitor(&workhorse);
		each_object(object_visitor);

		code_block_become_visitor code_block_visitor(&workhorse);
		each_code_block(code_block_visitor);
	}

	/* Since we may have introduced old->new references, need to revisit
	all objects and code blocks on a minor GC. */
	data->mark_all_cards();

	{
		code_block_write_barrier_visitor code_block_visitor(code);
		each_code_block(code_block_visitor);
	}
}
Exemple #27
0
// classes.tuple uses this to reshape tuples; tools.deploy.shaker uses this
// to coalesce equal but distinct quotations and wrappers.
// Calls gc
void factor_vm::primitive_become() {
  primitive_minor_gc();
  array* new_objects = untag_check<array>(ctx->pop());
  array* old_objects = untag_check<array>(ctx->pop());

  cell capacity = array_capacity(new_objects);
  if (capacity != array_capacity(old_objects))
    critical_error("bad parameters to become", 0);

  // Build the forwarding map
  std::map<object*, object*> become_map;

  for (cell i = 0; i < capacity; i++) {
    cell old_ptr = array_nth(old_objects, i);
    cell new_ptr = array_nth(new_objects, i);
    if (old_ptr != new_ptr)
      become_map[untag<object>(old_ptr)] = untag<object>(new_ptr);
  }

  // Update all references to old objects to point to new objects
  {
    slot_visitor<slot_become_fixup> visitor(this,
                                            slot_become_fixup(&become_map));
    visitor.visit_all_roots();

    auto object_become_func = [&](object* obj) {
      visitor.visit_slots(obj);
    };
    each_object(object_become_func);

    auto code_block_become_func = [&](code_block* compiled, cell size) {
      visitor.visit_code_block_objects(compiled);
      visitor.visit_embedded_literals(compiled);
      code->write_barrier(compiled);
    };
    each_code_block(code_block_become_func);
  }

  // Since we may have introduced old->new references, need to revisit
  // all objects and code blocks on a minor GC.
  data->mark_all_cards();
}
Exemple #28
0
void growable_byte_array::append_bytes(void *elts, cell len)
{
	cell new_size = count + len;
	factorvm *myvm = elements.myvm;
	if(new_size >= array_capacity(elements.untagged()))
		elements = myvm->reallot_array(elements.untagged(),new_size * 2);

	memcpy(&elements->data<u8>()[count],elts,len);

	count += len;
}
Exemple #29
0
// All quotations wants a stack frame, except if they contain:
//   1) calls to the special subprimitives, see #295.
//   2) mega cache lookups, see #651
bool quotation_jit::stack_frame_p() {
  cell length = array_capacity(elements.untagged());
  for (cell i = 0; i < length; i++) {
    cell obj = nth(i);
    cell tag = TAG(obj);
    if ((tag == WORD_TYPE && special_subprimitive_p(obj)) ||
        (tag == ARRAY_TYPE && mega_lookup_p(i, length)))
      return false;
  }
  return true;
}
Exemple #30
0
void jit::emit_relocation(cell relocation_template_) {
  data_root<byte_array> relocation_template(relocation_template_, parent);
  cell capacity =
      array_capacity(relocation_template.untagged()) / sizeof(relocation_entry);
  relocation_entry* relocations = relocation_template->data<relocation_entry>();
  for (cell i = 0; i < capacity; i++) {
    relocation_entry entry = relocations[i];
    relocation_entry new_entry(entry.rel_type(), entry.rel_class(),
                               entry.rel_offset() + code.count);
    relocation.append_bytes(&new_entry, sizeof(relocation_entry));
  }
}