2009-05-02 05:04:19 -04:00
|
|
|
#include "master.hpp"
|
|
|
|
|
2009-05-04 02:46:13 -04:00
|
|
|
namespace factor
|
|
|
|
{
|
|
|
|
|
2010-01-18 02:51:27 -05:00
|
|
|
cell factor_vm::compute_entry_point_address(cell obj)
|
2009-05-07 15:26:08 -04:00
|
|
|
{
|
|
|
|
switch(tagged<object>(obj).type())
|
|
|
|
{
|
|
|
|
case WORD_TYPE:
|
2010-01-18 02:51:27 -05:00
|
|
|
return (cell)untag<word>(obj)->entry_point;
|
2009-05-07 15:26:08 -04:00
|
|
|
case QUOTATION_TYPE:
|
2010-01-18 02:51:27 -05:00
|
|
|
return (cell)untag<quotation>(obj)->entry_point;
|
2009-05-07 15:26:08 -04:00
|
|
|
default:
|
|
|
|
critical_error("Expected word or quotation",obj);
|
2009-11-27 18:05:08 -05:00
|
|
|
return 0;
|
2009-05-07 15:26:08 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-01-18 02:51:27 -05:00
|
|
|
cell factor_vm::compute_entry_point_pic_address(word *w, cell tagged_quot)
|
2009-05-07 15:26:08 -04:00
|
|
|
{
|
2009-10-18 21:26:21 -04:00
|
|
|
if(!to_boolean(tagged_quot) || max_pic_size == 0)
|
2010-01-18 02:51:27 -05:00
|
|
|
return (cell)w->entry_point;
|
2009-05-07 15:26:08 -04:00
|
|
|
else
|
|
|
|
{
|
|
|
|
quotation *quot = untag<quotation>(tagged_quot);
|
2010-01-06 05:49:14 -05:00
|
|
|
if(quot_compiled_p(quot))
|
2010-01-18 02:51:27 -05:00
|
|
|
return (cell)quot->entry_point;
|
2009-05-12 04:09:15 -04:00
|
|
|
else
|
2010-01-18 02:51:27 -05:00
|
|
|
return (cell)w->entry_point;
|
2009-05-07 15:26:08 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-01-18 02:51:27 -05:00
|
|
|
cell factor_vm::compute_entry_point_pic_address(cell w_)
|
2009-11-27 18:05:08 -05:00
|
|
|
{
|
|
|
|
tagged<word> w(w_);
|
2010-01-18 02:51:27 -05:00
|
|
|
return compute_entry_point_pic_address(w.untagged(),w->pic_def);
|
2009-11-27 18:05:08 -05:00
|
|
|
}
|
|
|
|
|
2010-01-18 02:51:27 -05:00
|
|
|
cell factor_vm::compute_entry_point_pic_tail_address(cell w_)
|
2009-11-27 18:05:08 -05:00
|
|
|
{
|
|
|
|
tagged<word> w(w_);
|
2010-01-18 02:51:27 -05:00
|
|
|
return compute_entry_point_pic_address(w.untagged(),w->pic_tail_def);
|
2009-05-07 15:26:08 -04:00
|
|
|
}
|
|
|
|
|
2009-11-25 18:20:48 -05:00
|
|
|
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
|
2011-11-17 23:42:30 -05:00
|
|
|
FACTOR_ASSERT(array_capacity(elements.untagged()) == 5);
|
|
|
|
FACTOR_ASSERT(array_nth(elements.untagged(),4) == special_objects[PIC_MISS_WORD]
|
2009-11-25 18:20:48 -05:00
|
|
|
|| 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;
|
|
|
|
}
|
|
|
|
|
2009-11-28 20:48:26 -05:00
|
|
|
struct update_word_references_relocation_visitor {
|
2009-11-25 18:20:48 -05:00
|
|
|
factor_vm *parent;
|
2010-02-01 08:49:05 -05:00
|
|
|
bool reset_inline_caches;
|
2009-11-25 18:20:48 -05:00
|
|
|
|
2010-02-01 08:49:05 -05:00
|
|
|
update_word_references_relocation_visitor(
|
|
|
|
factor_vm *parent_,
|
|
|
|
bool reset_inline_caches_) :
|
|
|
|
parent(parent_),
|
|
|
|
reset_inline_caches(reset_inline_caches_) {}
|
2009-11-25 18:20:48 -05:00
|
|
|
|
2009-12-02 01:48:41 -05:00
|
|
|
void operator()(instruction_operand op)
|
2009-11-25 18:20:48 -05:00
|
|
|
{
|
2009-12-02 01:48:41 -05:00
|
|
|
switch(op.rel_type())
|
2009-11-25 18:20:48 -05:00
|
|
|
{
|
2010-01-18 02:51:27 -05:00
|
|
|
case RT_ENTRY_POINT:
|
2009-11-25 18:20:48 -05:00
|
|
|
{
|
|
|
|
code_block *compiled = op.load_code_block();
|
2009-12-02 06:27:48 -05:00
|
|
|
cell owner = compiled->owner;
|
2010-01-18 02:51:27 -05:00
|
|
|
if(to_boolean(owner))
|
|
|
|
op.store_value(parent->compute_entry_point_address(owner));
|
2009-11-25 18:20:48 -05:00
|
|
|
break;
|
|
|
|
}
|
2010-01-18 02:51:27 -05:00
|
|
|
case RT_ENTRY_POINT_PIC:
|
2009-11-25 18:20:48 -05:00
|
|
|
{
|
|
|
|
code_block *compiled = op.load_code_block();
|
2010-02-01 08:49:05 -05:00
|
|
|
if(reset_inline_caches || !compiled->pic_p())
|
|
|
|
{
|
|
|
|
cell owner = parent->code_block_owner(compiled);
|
|
|
|
if(to_boolean(owner))
|
|
|
|
op.store_value(parent->compute_entry_point_pic_address(owner));
|
|
|
|
}
|
2009-11-25 18:20:48 -05:00
|
|
|
break;
|
|
|
|
}
|
2010-01-18 02:51:27 -05:00
|
|
|
case RT_ENTRY_POINT_PIC_TAIL:
|
2009-11-25 18:20:48 -05:00
|
|
|
{
|
|
|
|
code_block *compiled = op.load_code_block();
|
2010-02-01 08:49:05 -05:00
|
|
|
if(reset_inline_caches || !compiled->pic_p())
|
|
|
|
{
|
|
|
|
cell owner = parent->code_block_owner(compiled);
|
|
|
|
if(to_boolean(owner))
|
|
|
|
op.store_value(parent->compute_entry_point_pic_tail_address(owner));
|
|
|
|
}
|
2009-11-25 18:20:48 -05:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/* 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. */
|
2010-02-01 08:49:05 -05:00
|
|
|
void factor_vm::update_word_references(code_block *compiled, bool reset_inline_caches)
|
2009-11-25 18:20:48 -05:00
|
|
|
{
|
2009-12-02 05:28:15 -05:00
|
|
|
if(code->uninitialized_p(compiled))
|
2009-12-02 02:09:08 -05:00
|
|
|
initialize_code_block(compiled);
|
2009-11-25 18:20:48 -05:00
|
|
|
/* update_word_references() is always applied to every block in
|
|
|
|
the code heap. Since it resets all call sites to point to
|
2010-01-18 02:51:27 -05:00
|
|
|
their canonical entry point (cold entry point for non-tail calls,
|
2009-11-25 18:20:48 -05:00
|
|
|
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. */
|
2010-02-01 08:49:05 -05:00
|
|
|
else if(reset_inline_caches && compiled->pic_p())
|
2009-12-02 06:27:48 -05:00
|
|
|
code->free(compiled);
|
2009-11-25 18:20:48 -05:00
|
|
|
else
|
|
|
|
{
|
2010-02-01 08:49:05 -05:00
|
|
|
update_word_references_relocation_visitor visitor(this,reset_inline_caches);
|
2009-12-02 01:48:41 -05:00
|
|
|
compiled->each_instruction_operand(visitor);
|
2009-11-25 18:20:48 -05:00
|
|
|
compiled->flush_icache();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-12-02 02:09:08 -05:00
|
|
|
/* Look up an external library symbol referenced by a compiled code block */
|
2011-09-12 03:56:24 -04:00
|
|
|
cell factor_vm::compute_dlsym_address(array *parameters, cell index)
|
2009-12-02 02:09:08 -05:00
|
|
|
{
|
2011-09-12 03:56:24 -04:00
|
|
|
cell symbol = array_nth(parameters,index);
|
|
|
|
cell library = array_nth(parameters,index + 1);
|
2009-12-02 02:09:08 -05:00
|
|
|
|
|
|
|
dll *d = (to_boolean(library) ? untag<dll>(library) : NULL);
|
|
|
|
|
2011-05-20 18:11:50 -04:00
|
|
|
void* undefined_symbol = (void*)factor::undefined_symbol;
|
|
|
|
undefined_symbol = FUNCTION_CODE_POINTER(undefined_symbol);
|
2010-01-16 09:43:22 -05:00
|
|
|
if(d != NULL && !d->handle)
|
2011-05-20 18:11:50 -04:00
|
|
|
return (cell)undefined_symbol;
|
2009-12-02 02:09:08 -05:00
|
|
|
|
|
|
|
switch(tagged<object>(symbol).type())
|
|
|
|
{
|
|
|
|
case BYTE_ARRAY_TYPE:
|
|
|
|
{
|
|
|
|
symbol_char *name = alien_offset(symbol);
|
|
|
|
void *sym = ffi_dlsym(d,name);
|
|
|
|
|
|
|
|
if(sym)
|
|
|
|
return (cell)sym;
|
|
|
|
else
|
2011-05-20 18:11:50 -04:00
|
|
|
return (cell)undefined_symbol;
|
2009-12-02 02:09:08 -05:00
|
|
|
}
|
|
|
|
case ARRAY_TYPE:
|
|
|
|
{
|
|
|
|
array *names = untag<array>(symbol);
|
|
|
|
for(cell i = 0; i < array_capacity(names); i++)
|
|
|
|
{
|
|
|
|
symbol_char *name = alien_offset(array_nth(names,i));
|
|
|
|
void *sym = ffi_dlsym(d,name);
|
|
|
|
|
|
|
|
if(sym)
|
|
|
|
return (cell)sym;
|
|
|
|
}
|
2011-05-20 18:11:50 -04:00
|
|
|
return (cell)undefined_symbol;
|
2009-12-02 02:09:08 -05:00
|
|
|
}
|
|
|
|
default:
|
|
|
|
critical_error("Bad symbol specifier",symbol);
|
2011-05-20 18:11:50 -04:00
|
|
|
return (cell)undefined_symbol;
|
2009-12-02 02:09:08 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-05-20 18:11:50 -04:00
|
|
|
#ifdef FACTOR_PPC
|
2011-09-12 03:56:24 -04:00
|
|
|
cell factor_vm::compute_dlsym_toc_address(array *parameters, cell index)
|
2011-05-20 18:11:50 -04:00
|
|
|
{
|
2011-09-12 03:56:24 -04:00
|
|
|
cell symbol = array_nth(parameters,index);
|
|
|
|
cell library = array_nth(parameters,index + 1);
|
2011-05-20 18:11:50 -04:00
|
|
|
|
|
|
|
dll *d = (to_boolean(library) ? untag<dll>(library) : NULL);
|
|
|
|
|
|
|
|
void* undefined_toc = (void*)factor::undefined_symbol;
|
|
|
|
undefined_toc = FUNCTION_TOC_POINTER(undefined_toc);
|
|
|
|
if(d != NULL && !d->handle)
|
|
|
|
return (cell)undefined_toc;
|
|
|
|
|
|
|
|
switch(tagged<object>(symbol).type())
|
|
|
|
{
|
|
|
|
case BYTE_ARRAY_TYPE:
|
|
|
|
{
|
|
|
|
symbol_char *name = alien_offset(symbol);
|
|
|
|
void* toc = ffi_dlsym_toc(d,name);
|
|
|
|
if(toc)
|
|
|
|
return (cell)toc;
|
|
|
|
else
|
|
|
|
return (cell)undefined_toc;
|
|
|
|
}
|
|
|
|
case ARRAY_TYPE:
|
|
|
|
{
|
|
|
|
array *names = untag<array>(symbol);
|
|
|
|
for(cell i = 0; i < array_capacity(names); i++)
|
|
|
|
{
|
|
|
|
symbol_char *name = alien_offset(array_nth(names,i));
|
|
|
|
void *toc = ffi_dlsym_toc(d,name);
|
|
|
|
|
|
|
|
if(toc)
|
|
|
|
return (cell)toc;
|
|
|
|
}
|
|
|
|
return (cell)undefined_toc;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
critical_error("Bad symbol specifier",symbol);
|
|
|
|
return (cell)undefined_toc;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2009-12-02 02:09:08 -05:00
|
|
|
cell factor_vm::compute_vm_address(cell arg)
|
|
|
|
{
|
|
|
|
return (cell)this + untag_fixnum(arg);
|
|
|
|
}
|
|
|
|
|
|
|
|
void factor_vm::store_external_address(instruction_operand op)
|
2009-12-02 01:54:16 -05:00
|
|
|
{
|
2011-09-12 03:56:24 -04:00
|
|
|
code_block *compiled = op.compiled;
|
2009-12-02 05:28:15 -05:00
|
|
|
array *parameters = (to_boolean(compiled->parameters) ? untag<array>(compiled->parameters) : NULL);
|
2011-09-12 03:56:24 -04:00
|
|
|
cell index = op.index;
|
2009-12-02 01:54:16 -05:00
|
|
|
|
|
|
|
switch(op.rel_type())
|
|
|
|
{
|
|
|
|
case RT_DLSYM:
|
2009-12-02 05:28:15 -05:00
|
|
|
op.store_value(compute_dlsym_address(parameters,index));
|
2009-12-02 01:54:16 -05:00
|
|
|
break;
|
|
|
|
case RT_THIS:
|
2010-01-18 02:51:27 -05:00
|
|
|
op.store_value((cell)compiled->entry_point());
|
2009-12-02 01:54:16 -05:00
|
|
|
break;
|
|
|
|
case RT_MEGAMORPHIC_CACHE_HITS:
|
2009-12-02 02:09:08 -05:00
|
|
|
op.store_value((cell)&dispatch_stats.megamorphic_cache_hits);
|
2009-12-02 01:54:16 -05:00
|
|
|
break;
|
|
|
|
case RT_VM:
|
2009-12-02 05:28:15 -05:00
|
|
|
op.store_value(compute_vm_address(array_nth(parameters,index)));
|
2009-12-02 01:54:16 -05:00
|
|
|
break;
|
|
|
|
case RT_CARDS_OFFSET:
|
2009-12-02 02:09:08 -05:00
|
|
|
op.store_value(cards_offset);
|
2009-12-02 01:54:16 -05:00
|
|
|
break;
|
|
|
|
case RT_DECKS_OFFSET:
|
2009-12-02 02:09:08 -05:00
|
|
|
op.store_value(decks_offset);
|
2009-12-02 01:54:16 -05:00
|
|
|
break;
|
2010-04-03 20:24:33 -04:00
|
|
|
#ifdef WINDOWS
|
|
|
|
case RT_EXCEPTION_HANDLER:
|
2010-04-04 14:53:17 -04:00
|
|
|
op.store_value((cell)&factor::exception_handler);
|
2010-04-03 20:24:33 -04:00
|
|
|
break;
|
2011-05-20 18:11:50 -04:00
|
|
|
#endif
|
|
|
|
#ifdef FACTOR_PPC
|
|
|
|
case RT_DLSYM_TOC:
|
|
|
|
op.store_value(compute_dlsym_toc_address(parameters,index));
|
|
|
|
break;
|
2010-04-03 20:24:33 -04:00
|
|
|
#endif
|
2011-09-14 04:08:32 -04:00
|
|
|
case RT_INLINE_CACHE_MISS:
|
|
|
|
op.store_value((cell)&factor::inline_cache_miss);
|
|
|
|
break;
|
2011-10-17 18:22:37 -04:00
|
|
|
case RT_SAFEPOINT:
|
|
|
|
op.store_value((cell)code->safepoint_page);
|
|
|
|
break;
|
2009-12-02 01:54:16 -05:00
|
|
|
default:
|
2010-04-30 21:33:42 -04:00
|
|
|
critical_error("Bad rel type in store_external_address()",op.rel_type());
|
2009-12-02 01:54:16 -05:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-12-02 05:55:48 -05:00
|
|
|
cell factor_vm::compute_here_address(cell arg, cell offset, code_block *compiled)
|
|
|
|
{
|
|
|
|
fixnum n = untag_fixnum(arg);
|
2010-01-18 02:51:27 -05:00
|
|
|
if(n >= 0)
|
|
|
|
return (cell)compiled->entry_point() + offset + n;
|
|
|
|
else
|
|
|
|
return (cell)compiled->entry_point() - n;
|
2009-12-02 05:55:48 -05:00
|
|
|
}
|
|
|
|
|
2009-12-02 02:09:08 -05:00
|
|
|
struct initial_code_block_visitor {
|
2009-10-18 21:31:59 -04:00
|
|
|
factor_vm *parent;
|
2009-12-02 05:28:15 -05:00
|
|
|
cell literals;
|
|
|
|
cell literal_index;
|
2009-10-03 09:47:05 -04:00
|
|
|
|
2009-12-02 05:28:15 -05:00
|
|
|
explicit initial_code_block_visitor(factor_vm *parent_, cell literals_)
|
|
|
|
: parent(parent_), literals(literals_), literal_index(0) {}
|
2009-10-03 09:47:05 -04:00
|
|
|
|
2009-12-02 05:28:15 -05:00
|
|
|
cell next_literal()
|
2009-10-03 09:47:05 -04:00
|
|
|
{
|
2009-12-02 05:28:15 -05:00
|
|
|
return array_nth(untag<array>(literals),literal_index++);
|
|
|
|
}
|
2009-11-28 20:48:26 -05:00
|
|
|
|
2009-12-02 05:28:15 -05:00
|
|
|
void operator()(instruction_operand op)
|
|
|
|
{
|
2009-12-02 01:48:41 -05:00
|
|
|
switch(op.rel_type())
|
2009-11-28 20:48:26 -05:00
|
|
|
{
|
2009-12-15 07:20:09 -05:00
|
|
|
case RT_LITERAL:
|
2009-12-02 05:28:15 -05:00
|
|
|
op.store_value(next_literal());
|
2009-11-28 20:48:26 -05:00
|
|
|
break;
|
2010-01-18 02:51:27 -05:00
|
|
|
case RT_ENTRY_POINT:
|
|
|
|
op.store_value(parent->compute_entry_point_address(next_literal()));
|
2009-11-28 20:48:26 -05:00
|
|
|
break;
|
2010-01-18 02:51:27 -05:00
|
|
|
case RT_ENTRY_POINT_PIC:
|
|
|
|
op.store_value(parent->compute_entry_point_pic_address(next_literal()));
|
2009-11-28 20:48:26 -05:00
|
|
|
break;
|
2010-01-18 02:51:27 -05:00
|
|
|
case RT_ENTRY_POINT_PIC_TAIL:
|
|
|
|
op.store_value(parent->compute_entry_point_pic_tail_address(next_literal()));
|
2009-12-02 05:28:15 -05:00
|
|
|
break;
|
2009-12-02 05:55:48 -05:00
|
|
|
case RT_HERE:
|
2011-09-12 03:56:24 -04:00
|
|
|
op.store_value(parent->compute_here_address(next_literal(),op.rel_offset(),op.compiled));
|
2009-12-02 05:55:48 -05:00
|
|
|
break;
|
2009-12-02 05:28:15 -05:00
|
|
|
case RT_UNTAGGED:
|
|
|
|
op.store_value(untag_fixnum(next_literal()));
|
2009-11-28 20:48:26 -05:00
|
|
|
break;
|
|
|
|
default:
|
2009-12-02 02:09:08 -05:00
|
|
|
parent->store_external_address(op);
|
2009-11-28 20:48:26 -05:00
|
|
|
break;
|
|
|
|
}
|
2009-10-03 09:47:05 -04:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2009-05-02 05:04:19 -04:00
|
|
|
/* Perform all fixups on a code block */
|
2010-02-01 08:49:05 -05:00
|
|
|
void factor_vm::initialize_code_block(code_block *compiled, cell literals)
|
2009-05-02 05:04:19 -04:00
|
|
|
{
|
2010-02-01 08:49:05 -05:00
|
|
|
initial_code_block_visitor visitor(this,literals);
|
2009-12-02 01:48:41 -05:00
|
|
|
compiled->each_instruction_operand(visitor);
|
2009-11-24 22:36:35 -05:00
|
|
|
compiled->flush_icache();
|
2009-12-21 21:49:21 -05:00
|
|
|
|
|
|
|
/* next time we do a minor GC, we have to trace this code block, since
|
|
|
|
the newly-installed instruction operands might point to literals in
|
|
|
|
nursery or aging */
|
|
|
|
code->write_barrier(compiled);
|
2009-05-02 05:04:19 -04:00
|
|
|
}
|
|
|
|
|
2010-02-01 08:49:05 -05:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2009-05-02 05:04:19 -04:00
|
|
|
/* Fixup labels. This is done at compile time, not image load time */
|
2009-09-23 14:05:46 -04:00
|
|
|
void factor_vm::fixup_labels(array *labels, code_block *compiled)
|
2009-05-02 05:04:19 -04:00
|
|
|
{
|
2009-05-04 05:50:24 -04:00
|
|
|
cell size = array_capacity(labels);
|
2009-05-02 05:04:19 -04:00
|
|
|
|
2009-12-02 01:48:41 -05:00
|
|
|
for(cell i = 0; i < size; i += 3)
|
2009-05-02 05:04:19 -04:00
|
|
|
{
|
2009-12-02 01:48:41 -05:00
|
|
|
relocation_class rel_class = (relocation_class)untag_fixnum(array_nth(labels,i));
|
2009-05-04 05:50:24 -04:00
|
|
|
cell offset = untag_fixnum(array_nth(labels,i + 1));
|
|
|
|
cell target = untag_fixnum(array_nth(labels,i + 2));
|
2009-05-02 05:04:19 -04:00
|
|
|
|
2009-12-02 01:48:41 -05:00
|
|
|
relocation_entry new_entry(RT_HERE,rel_class,offset);
|
|
|
|
|
|
|
|
instruction_operand op(new_entry,compiled,0);
|
2010-01-18 02:51:27 -05:00
|
|
|
op.store_value(target + (cell)compiled->entry_point());
|
2009-05-02 05:04:19 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Might GC */
|
2009-10-20 10:37:24 -04:00
|
|
|
code_block *factor_vm::allot_code_block(cell size, code_block_type type)
|
2009-05-02 05:04:19 -04:00
|
|
|
{
|
2009-10-24 22:24:06 -04:00
|
|
|
code_block *block = code->allocator->allot(size + sizeof(code_block));
|
2009-05-02 05:04:19 -04:00
|
|
|
|
2009-10-16 12:39:22 -04:00
|
|
|
/* If allocation failed, do a full GC and compact the code heap.
|
|
|
|
A full GC that occurs as a result of the data heap filling up does not
|
|
|
|
trigger a compaction. This setup ensures that most GCs do not compact
|
|
|
|
the code heap, but if the code fills up, it probably means it will be
|
|
|
|
fragmented after GC anyway, so its best to compact. */
|
2009-05-02 05:04:19 -04:00
|
|
|
if(block == NULL)
|
|
|
|
{
|
2009-10-16 12:39:22 -04:00
|
|
|
primitive_compact_gc();
|
2009-10-20 16:15:05 -04:00
|
|
|
block = code->allocator->allot(size + sizeof(code_block));
|
2009-05-02 05:04:19 -04:00
|
|
|
|
|
|
|
/* Insufficient room even after code GC, give up */
|
|
|
|
if(block == NULL)
|
|
|
|
{
|
2009-10-26 23:08:35 -04:00
|
|
|
std::cout << "Code heap used: " << code->allocator->occupied_space() << "\n";
|
|
|
|
std::cout << "Code heap free: " << code->allocator->free_space() << "\n";
|
2009-05-02 05:04:19 -04:00
|
|
|
fatal_error("Out of memory in add-compiled-block",0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-10-24 22:24:06 -04:00
|
|
|
block->set_type(type);
|
|
|
|
return block;
|
2009-05-02 05:04:19 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Might GC */
|
2011-11-25 21:58:21 -05:00
|
|
|
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)
|
2009-05-02 05:04:19 -04:00
|
|
|
{
|
2009-11-02 19:10:34 -05:00
|
|
|
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);
|
2009-12-02 05:28:15 -05:00
|
|
|
data_root<array> parameters(parameters_,this);
|
2009-11-02 19:10:34 -05:00
|
|
|
data_root<array> literals(literals_,this);
|
2009-05-02 05:04:19 -04:00
|
|
|
|
2009-10-20 13:19:02 -04:00
|
|
|
cell code_length = array_capacity(code.untagged());
|
2009-10-06 06:52:45 -04:00
|
|
|
code_block *compiled = allot_code_block(code_length,type);
|
2009-05-02 10:19:09 -04:00
|
|
|
|
2009-10-06 07:25:07 -04:00
|
|
|
compiled->owner = owner.value();
|
|
|
|
|
2009-05-02 10:19:09 -04:00
|
|
|
/* slight space optimization */
|
2009-10-06 02:31:39 -04:00
|
|
|
if(relocation.type() == BYTE_ARRAY_TYPE && array_capacity(relocation.untagged()) == 0)
|
2009-10-18 21:26:21 -04:00
|
|
|
compiled->relocation = false_object;
|
2009-10-06 02:31:39 -04:00
|
|
|
else
|
|
|
|
compiled->relocation = relocation.value();
|
|
|
|
|
2009-12-02 05:28:15 -05:00
|
|
|
if(parameters.type() == ARRAY_TYPE && array_capacity(parameters.untagged()) == 0)
|
|
|
|
compiled->parameters = false_object;
|
2009-05-02 10:19:09 -04:00
|
|
|
else
|
2009-12-02 05:28:15 -05:00
|
|
|
compiled->parameters = parameters.value();
|
2009-05-02 05:04:19 -04:00
|
|
|
|
|
|
|
/* code */
|
2009-05-02 10:19:09 -04:00
|
|
|
memcpy(compiled + 1,code.untagged() + 1,code_length);
|
2009-05-02 05:04:19 -04:00
|
|
|
|
|
|
|
/* fixup labels */
|
2009-10-18 21:26:21 -04:00
|
|
|
if(to_boolean(labels.value()))
|
2009-05-04 05:50:24 -04:00
|
|
|
fixup_labels(labels.as<array>().untagged(),compiled);
|
2009-05-02 05:04:19 -04:00
|
|
|
|
2011-11-25 22:23:07 -05:00
|
|
|
compiled->set_stack_frame_size(frame_size_untagged);
|
2011-11-25 21:58:21 -05:00
|
|
|
|
2009-12-21 21:49:21 -05:00
|
|
|
/* 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 */
|
2009-12-02 05:28:15 -05:00
|
|
|
this->code->uninitialized_blocks.insert(std::make_pair(compiled,literals.value()));
|
2011-11-29 23:18:51 -05:00
|
|
|
this->code->all_blocks.insert((cell)compiled);
|
2009-05-02 05:04:19 -04:00
|
|
|
|
2009-12-21 21:49:21 -05:00
|
|
|
/* 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);
|
|
|
|
|
2009-05-02 05:04:19 -04:00
|
|
|
return compiled;
|
|
|
|
}
|
2009-05-04 02:46:13 -04:00
|
|
|
|
2011-09-12 03:56:24 -04:00
|
|
|
/* Find the RT_DLSYM relocation nearest to the given return address. */
|
|
|
|
struct find_symbol_at_address_visitor {
|
|
|
|
factor_vm *parent;
|
|
|
|
cell return_address;
|
|
|
|
cell symbol;
|
|
|
|
cell library;
|
|
|
|
|
|
|
|
find_symbol_at_address_visitor(factor_vm *parent_, cell return_address_) :
|
|
|
|
parent(parent_), return_address(return_address_),
|
|
|
|
symbol(false_object), library(false_object) { }
|
|
|
|
|
|
|
|
void operator()(instruction_operand op)
|
|
|
|
{
|
2011-09-13 23:43:07 -04:00
|
|
|
if(op.rel_type() == RT_DLSYM && op.pointer <= return_address)
|
2011-09-12 03:56:24 -04:00
|
|
|
{
|
|
|
|
code_block *compiled = op.compiled;
|
|
|
|
array *parameters = untag<array>(compiled->parameters);
|
|
|
|
cell index = op.index;
|
|
|
|
symbol = array_nth(parameters,index);
|
|
|
|
library = array_nth(parameters,index + 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/* References to undefined symbols are patched up to call this function on
|
|
|
|
image load. It finds the symbol and library, and throws an error. */
|
|
|
|
void factor_vm::undefined_symbol()
|
|
|
|
{
|
|
|
|
stack_frame *frame = innermost_stack_frame(ctx->callstack_bottom,
|
|
|
|
ctx->callstack_top);
|
|
|
|
code_block *compiled = frame_code(frame);
|
|
|
|
cell return_address = (cell)FRAME_RETURN_ADDRESS(frame, this);
|
|
|
|
find_symbol_at_address_visitor visitor(this, return_address);
|
|
|
|
compiled->each_instruction_operand(visitor);
|
|
|
|
if (!to_boolean(visitor.symbol))
|
|
|
|
critical_error("Can't find RT_DLSYM at return address", return_address);
|
|
|
|
else
|
|
|
|
general_error(ERROR_UNDEFINED_SYMBOL,visitor.symbol,visitor.library);
|
|
|
|
}
|
|
|
|
|
|
|
|
void undefined_symbol()
|
|
|
|
{
|
|
|
|
return current_vm()->undefined_symbol();
|
|
|
|
}
|
|
|
|
|
2009-05-04 02:46:13 -04:00
|
|
|
}
|