factor/vm/run.c

352 lines
6.4 KiB
C
Raw Normal View History

2004-07-16 02:26:21 -04:00
#include "factor.h"
2005-01-01 19:30:57 -05:00
INLINE void execute(F_WORD* word)
{
((XT)(word->xt))(word);
2005-01-01 19:30:57 -05:00
}
2004-07-16 02:26:21 -04:00
2006-06-27 03:40:07 -04:00
INLINE void push_callframe(void)
2006-05-17 14:55:46 -04:00
{
put(cs + CELLS,callframe);
put(cs + CELLS * 2,callframe_scan);
put(cs + CELLS * 3,callframe_end);
/* update the pointer last, so that if we have a memory protection error
above, we don't have garbage stored as live data */
2006-06-27 03:40:07 -04:00
cs += CELLS * 3;
}
INLINE void set_callframe(CELL quot)
{
F_ARRAY *untagged = (F_ARRAY*)UNTAG(quot);
type_check(QUOTATION_TYPE,quot);
callframe = quot;
callframe_scan = AREF(untagged,0);
callframe_end = AREF(untagged,array_capacity(untagged));
}
2006-05-17 14:55:46 -04:00
2006-06-27 03:40:07 -04:00
void call(CELL quot)
{
2006-05-17 14:55:46 -04:00
if(quot == F)
return;
/* tail call optimization */
if(callframe_scan < callframe_end)
2006-06-27 03:40:07 -04:00
push_callframe();
2006-05-17 14:55:46 -04:00
2006-06-27 03:40:07 -04:00
set_callframe(quot);
2006-05-17 14:55:46 -04:00
}
2006-10-15 00:10:54 -04:00
/* Called from interpreter() */
void handle_error(void)
2004-07-16 02:26:21 -04:00
{
if(throwing)
2004-11-06 15:51:17 -05:00
{
gc_off = false;
2006-11-02 18:29:11 -05:00
extra_roots = stack_chain->extra_roots;
2004-11-09 12:29:25 -05:00
if(thrown_keep_stacks)
{
ds = thrown_ds;
2006-05-14 23:09:47 -04:00
rs = thrown_rs;
2004-11-09 12:29:25 -05:00
}
else
fix_stacks();
2004-11-06 15:51:17 -05:00
dpush(thrown_error);
dpush(thrown_native_stack_trace);
2004-11-06 15:51:17 -05:00
/* Notify any 'catch' blocks */
2006-06-27 03:40:07 -04:00
push_callframe();
set_callframe(userenv[BREAK_ENV]);
throwing = false;
2004-11-06 15:51:17 -05:00
}
}
2006-10-15 00:10:54 -04:00
void interpreter_loop(void)
{
CELL next;
2004-07-16 02:26:21 -04:00
for(;;)
{
2006-05-17 14:55:46 -04:00
if(callframe_scan == callframe_end)
2004-07-16 02:26:21 -04:00
{
if(cs_bot - cs == CELLS)
{
if(stack_chain->next)
return;
general_error(ERROR_CS_UNDERFLOW,F,F,false);
}
2006-05-17 14:55:46 -04:00
callframe_end = get(cs);
callframe_scan = get(cs - CELLS);
callframe = get(cs - CELLS * 2);
cs -= CELLS * 3;
2004-07-16 02:26:21 -04:00
continue;
}
2006-05-17 14:55:46 -04:00
next = get(callframe_scan);
callframe_scan += CELLS;
2004-07-16 02:26:21 -04:00
2006-05-18 01:08:09 -04:00
switch(TAG(next))
{
case WORD_TYPE:
2005-01-01 19:30:57 -05:00
execute(untag_word_fast(next));
break;
case WRAPPER_TYPE:
dpush(untag_wrapper_fast(next)->object);
break;
default:
dpush(next);
break;
}
2004-07-16 02:26:21 -04:00
}
}
2006-10-15 00:10:54 -04:00
void interpreter(void)
{
stack_chain->native_stack_pointer = native_stack_pointer();
SETJMP(stack_chain->toplevel);
handle_error();
2006-10-15 00:10:54 -04:00
interpreter_loop();
}
/* Called by compiled callbacks after nest_stacks() and boxing registers */
void run_callback(CELL quot)
{
call(quot);
2006-10-15 00:10:54 -04:00
run();
}
2004-07-16 02:26:21 -04:00
/* XT of deferred words */
2005-01-01 19:30:57 -05:00
void undefined(F_WORD* word)
2004-07-16 02:26:21 -04:00
{
general_error(ERROR_UNDEFINED_WORD,tag_word(word),F,true);
2004-07-16 02:26:21 -04:00
}
/* XT of compound definitions */
2005-01-01 19:30:57 -05:00
void docol(F_WORD* word)
2004-07-16 02:26:21 -04:00
{
call(word->def);
2004-09-28 00:24:36 -04:00
}
/* pushes word parameter */
2005-01-01 19:30:57 -05:00
void dosym(F_WORD* word)
2004-09-28 00:24:36 -04:00
{
dpush(word->def);
2004-07-16 02:26:21 -04:00
}
void primitive_execute(void)
{
2005-01-01 19:30:57 -05:00
execute(untag_word(dpop()));
2004-07-16 02:26:21 -04:00
}
void primitive_call(void)
{
2004-08-23 01:13:09 -04:00
call(dpop());
2004-07-16 02:26:21 -04:00
}
void primitive_ifte(void)
{
2006-05-18 01:08:09 -04:00
ds -= CELLS * 3;
2006-07-24 01:22:11 -04:00
call(get(ds + CELLS) == F ? get(ds + CELLS * 3) : get(ds + CELLS * 2));
2004-07-16 02:26:21 -04:00
}
void primitive_dispatch(void)
{
F_ARRAY *a = untag_array_fast(dpop());
F_FIXNUM n = untag_fixnum_fast(dpop());
call(get(AREF(a,n)));
}
2004-07-16 02:26:21 -04:00
void primitive_getenv(void)
{
2005-04-25 21:39:34 -04:00
F_FIXNUM e = untag_fixnum_fast(dpeek());
2004-08-20 18:48:08 -04:00
drepl(userenv[e]);
2004-07-16 02:26:21 -04:00
}
void primitive_setenv(void)
{
2005-04-25 21:39:34 -04:00
F_FIXNUM e = untag_fixnum_fast(dpop());
2004-07-16 02:26:21 -04:00
CELL value = dpop();
2004-08-20 18:48:08 -04:00
userenv[e] = value;
2004-07-16 02:26:21 -04:00
}
2006-07-07 00:07:18 -04:00
void primitive_exit(void)
{
2006-10-31 00:52:02 -05:00
exit(unbox_signed_cell());
2006-07-07 00:07:18 -04:00
}
void primitive_os_env(void)
{
2006-10-31 15:48:34 -05:00
char *name = unbox_char_string();
char *value = getenv(name);
2006-07-07 00:07:18 -04:00
if(value == NULL)
dpush(F);
else
2006-10-31 15:48:34 -05:00
box_char_string(value);
2006-07-07 00:07:18 -04:00
}
void primitive_eq(void)
{
2006-07-24 01:22:11 -04:00
CELL lhs = dpop();
CELL rhs = dpeek();
drepl((lhs == rhs) ? T : F);
2006-07-07 00:07:18 -04:00
}
void primitive_millis(void)
{
2006-10-31 15:48:34 -05:00
box_unsigned_8(current_millis());
2006-07-07 00:07:18 -04:00
}
void primitive_type(void)
{
drepl(tag_fixnum(type_of(dpeek())));
}
void primitive_tag(void)
{
drepl(tag_fixnum(TAG(dpeek())));
}
void primitive_slot(void)
{
F_FIXNUM slot = untag_fixnum_fast(dpop());
CELL obj = UNTAG(dpop());
dpush(get(SLOT(obj,slot)));
}
void primitive_set_slot(void)
{
F_FIXNUM slot = untag_fixnum_fast(dpop());
CELL obj = UNTAG(dpop());
CELL value = dpop();
2006-11-02 03:00:02 -05:00
set_slot(obj,slot,value);
}
void primitive_clone(void)
{
2006-10-31 00:52:02 -05:00
CELL size = object_size(dpeek());
void *new_obj = allot(size);
CELL tag = TAG(dpeek());
memcpy(new_obj,(void*)UNTAG(dpeek()),size);
drepl(RETAG(new_obj,tag));
}
2006-07-07 00:07:18 -04:00
void fatal_error(char* msg, CELL tagged)
{
fprintf(stderr,"Fatal error: %s %lx\n",msg,tagged);
2006-07-07 00:07:18 -04:00
exit(1);
}
void critical_error(char* msg, CELL tagged)
{
fprintf(stderr,"Critical error: %s %lx\n",msg,tagged);
2006-07-07 00:07:18 -04:00
factorbug();
}
void early_error(CELL error)
{
if(userenv[BREAK_ENV] == F)
{
/* Crash at startup */
fprintf(stderr,"Error during startup: ");
print_obj(error);
fprintf(stderr,"\n");
factorbug();
}
}
/* allocates memory */
CELL allot_native_stack_trace(void)
{
F_STACK_FRAME *frame = native_stack_pointer();
GROWABLE_ARRAY(array);
while((CELL)frame < (CELL)stack_chain->native_stack_pointer)
{
REGISTER_ARRAY(array);
CELL cell = allot_cell((CELL)frame->return_address);
UNREGISTER_ARRAY(array);
GROWABLE_ADD(array,cell);
if((CELL)frame->previous <= (CELL)frame)
2006-11-16 00:12:43 -05:00
{
fprintf(stderr,"Factor warning: unusual C stack layout\n");
fflush(stderr);
break;
}
frame = frame->previous;
}
GROWABLE_TRIM(array);
return tag_object(array);
}
2006-07-07 00:07:18 -04:00
void throw_error(CELL error, bool keep_stacks)
{
early_error(error);
REGISTER_ROOT(error);
thrown_native_stack_trace = F; /* allot_native_stack_trace(); */
UNREGISTER_ROOT(error);
2006-07-07 00:07:18 -04:00
throwing = true;
thrown_error = error;
thrown_keep_stacks = keep_stacks;
thrown_ds = ds;
thrown_rs = rs;
2006-10-15 00:10:54 -04:00
/* Return to interpreter() function */
2006-07-07 00:07:18 -04:00
LONGJMP(stack_chain->toplevel,1);
}
void primitive_throw(void)
{
throw_error(dpop(),true);
}
void primitive_die(void)
{
factorbug();
}
void general_error(F_ERRORTYPE error, CELL arg1, CELL arg2, bool keep_stacks)
{
2006-10-31 00:52:02 -05:00
throw_error(allot_array_4(userenv[ERROR_ENV],
2006-07-07 00:07:18 -04:00
tag_fixnum(error),arg1,arg2),keep_stacks);
}
2006-10-31 00:52:02 -05:00
void memory_protection_error(CELL addr, int signal)
{
gc_off = true;
2006-10-31 00:52:02 -05:00
if(in_page(addr, ds_bot, 0, -1))
general_error(ERROR_DS_UNDERFLOW,F,F,false);
2006-10-31 00:52:02 -05:00
else if(in_page(addr, ds_bot, ds_size, 0))
general_error(ERROR_DS_OVERFLOW,F,F,false);
2006-10-31 00:52:02 -05:00
else if(in_page(addr, rs_bot, 0, -1))
general_error(ERROR_RS_UNDERFLOW,F,F,false);
2006-10-31 00:52:02 -05:00
else if(in_page(addr, rs_bot, rs_size, 0))
general_error(ERROR_RS_OVERFLOW,F,F,false);
2006-10-31 00:52:02 -05:00
else if(in_page(addr, cs_bot, 0, -1))
general_error(ERROR_CS_UNDERFLOW,F,F,false);
2006-10-31 00:52:02 -05:00
else if(in_page(addr, cs_bot, cs_size, 0))
general_error(ERROR_CS_OVERFLOW,F,F,false);
2006-10-31 15:48:34 -05:00
else if(in_page(addr, nursery.limit, 0, 0))
2006-11-02 03:00:02 -05:00
critical_error("Out of memory in allot",0);
signal_error(signal);
}
2006-07-07 00:07:18 -04:00
void signal_error(int signal)
{
gc_off = true;
2006-07-07 00:07:18 -04:00
general_error(ERROR_SIGNAL,tag_fixnum(signal),F,false);
}
void type_error(CELL type, CELL tagged)
{
general_error(ERROR_TYPE,tag_fixnum(type),tagged,true);
}