Clean up exception handling in callbacks
parent
5e41efe8e2
commit
9e7af4d8b4
|
@ -1,8 +1,5 @@
|
||||||
- if two tasks write to a unix stream, the buffer can overflow
|
- if two tasks write to a unix stream, the buffer can overflow
|
||||||
- x86 SIB addressing modes
|
- x86 SIB addressing modes
|
||||||
- exceptions inside callbacks are broken:
|
|
||||||
- we need to unwind the stacks to the level where the exception handler
|
|
||||||
was set
|
|
||||||
- "localhost" 50 <client> won't fail
|
- "localhost" 50 <client> won't fail
|
||||||
- compiled gc check slows things down
|
- compiled gc check slows things down
|
||||||
|
|
||||||
|
|
|
@ -55,7 +55,8 @@ M: alien-callback-error summary ( error -- )
|
||||||
: linearize-callback ( node -- )
|
: linearize-callback ( node -- )
|
||||||
dup alien-callback-xt [
|
dup alien-callback-xt [
|
||||||
dup alien-callback-parameters registers>objects
|
dup alien-callback-parameters registers>objects
|
||||||
dup alien-callback-quot %alien-callback ,
|
dup alien-callback-quot \ init-error-handler swons
|
||||||
|
%alien-callback ,
|
||||||
unbox-return
|
unbox-return
|
||||||
%return ,
|
%return ,
|
||||||
] make-linear ;
|
] make-linear ;
|
||||||
|
|
|
@ -14,8 +14,7 @@ TUPLE: no-method object generic ;
|
||||||
[ >c call f c> drop f ] callcc1 nip ; inline
|
[ >c call f c> drop f ] callcc1 nip ; inline
|
||||||
|
|
||||||
: rethrow ( error -- )
|
: rethrow ( error -- )
|
||||||
catchstack* empty?
|
catchstack* empty? [ die ] [ c> continue-with ] if ;
|
||||||
[ die "Can't happen" throw ] [ c> continue-with ] if ;
|
|
||||||
|
|
||||||
: cleanup ( try cleanup -- | try: -- | cleanup: -- )
|
: cleanup ( try cleanup -- | try: -- | cleanup: -- )
|
||||||
[ >c >r call c> drop r> call ]
|
[ >c >r call c> drop r> call ]
|
||||||
|
|
|
@ -12,9 +12,9 @@ FUNCTION: void callback_test_1 void* callback ; compiled
|
||||||
|
|
||||||
[ ] [ callback-1 callback_test_1 ] unit-test
|
[ ] [ callback-1 callback_test_1 ] unit-test
|
||||||
|
|
||||||
! : callback-2 "void" { } [ 5 throw ] alien-callback ; compiled
|
: callback-2 "void" { } [ [ 5 throw ] catch drop ] alien-callback ; compiled
|
||||||
!
|
|
||||||
! [ 5 ] [ [ callback-2 callback_test_1 ] catch ] unit-test
|
[ ] [ callback-2 callback_test_1 ] unit-test
|
||||||
|
|
||||||
: callback-3 "void" { } [ 5 "x" set ] alien-callback ; compiled
|
: callback-3 "void" { } [ 5 "x" set ] alien-callback ; compiled
|
||||||
|
|
||||||
|
|
|
@ -37,7 +37,7 @@ void throw_error(CELL error, bool keep_stacks)
|
||||||
thrown_executing = executing;
|
thrown_executing = executing;
|
||||||
|
|
||||||
/* Return to run() method */
|
/* Return to run() method */
|
||||||
LONGJMP(toplevel,1);
|
LONGJMP(stack_chain->toplevel,1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void primitive_throw(void)
|
void primitive_throw(void)
|
||||||
|
|
17
native/gc.c
17
native/gc.c
|
@ -74,16 +74,21 @@ void collect_roots(void)
|
||||||
|
|
||||||
while(stacks)
|
while(stacks)
|
||||||
{
|
{
|
||||||
copy_handle(&stacks->callframe);
|
/* these two pointers are only set in inactive states */
|
||||||
|
if(stacks != stack_chain)
|
||||||
CELL bottom = stacks->ds_region->start;
|
{
|
||||||
CELL top = stacks->ds;
|
copy_handle(&stacks->callframe);
|
||||||
|
copy_handle(&stacks->catch_save);
|
||||||
|
}
|
||||||
|
|
||||||
|
CELL bottom = stacks->data_region->start;
|
||||||
|
CELL top = stacks->data;
|
||||||
|
|
||||||
for(ptr = bottom; ptr <= top; ptr += CELLS)
|
for(ptr = bottom; ptr <= top; ptr += CELLS)
|
||||||
copy_handle((CELL*)ptr);
|
copy_handle((CELL*)ptr);
|
||||||
|
|
||||||
bottom = stacks->cs_region->start;
|
bottom = stacks->call_region->start;
|
||||||
top = stacks->cs;
|
top = stacks->call;
|
||||||
|
|
||||||
for(ptr = bottom; ptr <= top; ptr += CELLS)
|
for(ptr = bottom; ptr <= top; ptr += CELLS)
|
||||||
copy_handle((CELL*)ptr);
|
copy_handle((CELL*)ptr);
|
||||||
|
|
|
@ -7,14 +7,14 @@ void platform_run()
|
||||||
{
|
{
|
||||||
for(;;)
|
for(;;)
|
||||||
{
|
{
|
||||||
SETJMP(toplevel);
|
SETJMP(stack_chain->toplevel);
|
||||||
handle_error();
|
handle_error();
|
||||||
NS_DURING
|
NS_DURING
|
||||||
run(false);
|
run();
|
||||||
NS_VOIDRETURN;
|
NS_VOIDRETURN;
|
||||||
NS_HANDLER
|
NS_HANDLER
|
||||||
general_error(ERROR_OBJECTIVE_C,
|
general_error(ERROR_OBJECTIVE_C,
|
||||||
tag_object(make_alien(F,localException)),
|
tag_object(make_alien(F,(CELL)localException)),
|
||||||
true);
|
true);
|
||||||
NS_ENDHANDLER
|
NS_ENDHANDLER
|
||||||
}
|
}
|
||||||
|
|
14
native/run.c
14
native/run.c
|
@ -31,16 +31,10 @@ void handle_error(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void run(bool handle_errors)
|
void run(void)
|
||||||
{
|
{
|
||||||
CELL next;
|
CELL next;
|
||||||
|
|
||||||
if(handle_errors)
|
|
||||||
{
|
|
||||||
SETJMP(toplevel);
|
|
||||||
handle_error();
|
|
||||||
}
|
|
||||||
|
|
||||||
for(;;)
|
for(;;)
|
||||||
{
|
{
|
||||||
if(callframe == F)
|
if(callframe == F)
|
||||||
|
@ -74,14 +68,16 @@ void run(bool handle_errors)
|
||||||
|
|
||||||
void run_toplevel(void)
|
void run_toplevel(void)
|
||||||
{
|
{
|
||||||
run(true);
|
SETJMP(stack_chain->toplevel);
|
||||||
|
handle_error();
|
||||||
|
run();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Called by compiled callbacks after nest_stacks() and boxing registers */
|
/* Called by compiled callbacks after nest_stacks() and boxing registers */
|
||||||
void run_callback(CELL quot)
|
void run_callback(CELL quot)
|
||||||
{
|
{
|
||||||
call(quot);
|
call(quot);
|
||||||
run(false);
|
platform_run();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* XT of deferred words */
|
/* XT of deferred words */
|
||||||
|
|
|
@ -22,9 +22,6 @@
|
||||||
/* TAGGED user environment data; see getenv/setenv prims */
|
/* TAGGED user environment data; see getenv/setenv prims */
|
||||||
DLLEXPORT CELL userenv[USER_ENV];
|
DLLEXPORT CELL userenv[USER_ENV];
|
||||||
|
|
||||||
/* Error handlers restore this */
|
|
||||||
JMP_BUF toplevel;
|
|
||||||
|
|
||||||
INLINE CELL dpop(void)
|
INLINE CELL dpop(void)
|
||||||
{
|
{
|
||||||
CELL value = get(ds);
|
CELL value = get(ds);
|
||||||
|
@ -79,7 +76,7 @@ INLINE void call(CELL quot)
|
||||||
}
|
}
|
||||||
|
|
||||||
void handle_error();
|
void handle_error();
|
||||||
void run(bool handle_errors);
|
void run(void);
|
||||||
void run_toplevel(void);
|
void run_toplevel(void);
|
||||||
DLLEXPORT void run_callback(CELL quot);
|
DLLEXPORT void run_callback(CELL quot);
|
||||||
void platform_run(void);
|
void platform_run(void);
|
||||||
|
|
|
@ -12,13 +12,13 @@ void reset_callstack(void)
|
||||||
|
|
||||||
void fix_stacks(void)
|
void fix_stacks(void)
|
||||||
{
|
{
|
||||||
if(STACK_UNDERFLOW(ds,stack_chain->ds_region))
|
if(STACK_UNDERFLOW(ds,stack_chain->data_region))
|
||||||
reset_datastack();
|
reset_datastack();
|
||||||
else if(STACK_OVERFLOW(ds,stack_chain->ds_region))
|
else if(STACK_OVERFLOW(ds,stack_chain->data_region))
|
||||||
reset_datastack();
|
reset_datastack();
|
||||||
else if(STACK_UNDERFLOW(cs,stack_chain->cs_region))
|
else if(STACK_UNDERFLOW(cs,stack_chain->call_region))
|
||||||
reset_callstack();
|
reset_callstack();
|
||||||
else if(STACK_OVERFLOW(cs,stack_chain->cs_region))
|
else if(STACK_OVERFLOW(cs,stack_chain->call_region))
|
||||||
reset_callstack();
|
reset_callstack();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,8 +26,8 @@ void fix_stacks(void)
|
||||||
in registers, so callbacks must save and restore the correct values */
|
in registers, so callbacks must save and restore the correct values */
|
||||||
void save_stacks(void)
|
void save_stacks(void)
|
||||||
{
|
{
|
||||||
stack_chain->ds = ds;
|
stack_chain->data = ds;
|
||||||
stack_chain->cs = cs;
|
stack_chain->call = cs;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* called on entry into a compiled callback */
|
/* called on entry into a compiled callback */
|
||||||
|
@ -45,12 +45,14 @@ void nest_stacks(void)
|
||||||
- Factor callback returns
|
- Factor callback returns
|
||||||
- C function restores registers
|
- C function restores registers
|
||||||
- C function returns to Factor code */
|
- C function returns to Factor code */
|
||||||
new_stacks->ds_save = ds;
|
new_stacks->data_save = ds;
|
||||||
new_stacks->cs_save = cs;
|
new_stacks->call_save = cs;
|
||||||
|
|
||||||
new_stacks->callframe = callframe;
|
new_stacks->callframe = callframe;
|
||||||
new_stacks->ds_region = alloc_bounded_block(ds_size);
|
new_stacks->catch_save = userenv[CATCHSTACK_ENV];
|
||||||
new_stacks->cs_region = alloc_bounded_block(cs_size);
|
|
||||||
|
new_stacks->data_region = alloc_bounded_block(ds_size);
|
||||||
|
new_stacks->call_region = alloc_bounded_block(cs_size);
|
||||||
new_stacks->next = stack_chain;
|
new_stacks->next = stack_chain;
|
||||||
stack_chain = new_stacks;
|
stack_chain = new_stacks;
|
||||||
callframe = F;
|
callframe = F;
|
||||||
|
@ -61,13 +63,15 @@ void nest_stacks(void)
|
||||||
/* called when leaving a compiled callback */
|
/* called when leaving a compiled callback */
|
||||||
void unnest_stacks(void)
|
void unnest_stacks(void)
|
||||||
{
|
{
|
||||||
dealloc_bounded_block(stack_chain->ds_region);
|
dealloc_bounded_block(stack_chain->data_region);
|
||||||
dealloc_bounded_block(stack_chain->cs_region);
|
dealloc_bounded_block(stack_chain->call_region);
|
||||||
|
|
||||||
ds = stack_chain->ds_save;
|
ds = stack_chain->data_save;
|
||||||
cs = stack_chain->cs_save;
|
cs = stack_chain->call_save;
|
||||||
|
|
||||||
callframe = stack_chain->callframe;
|
callframe = stack_chain->callframe;
|
||||||
|
userenv[CATCHSTACK_ENV] = stack_chain->catch_save;
|
||||||
|
|
||||||
stack_chain = stack_chain->next;
|
stack_chain = stack_chain->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,20 +1,32 @@
|
||||||
typedef struct _STACKS {
|
typedef struct _STACKS {
|
||||||
CELL ds;
|
/* current datastack top pointer */
|
||||||
CELL ds_save;
|
CELL data;
|
||||||
BOUNDED_BLOCK *ds_region;
|
/* saved contents of ds register on entry to callback */
|
||||||
CELL cs;
|
CELL data_save;
|
||||||
CELL cs_save;
|
/* memory region holding current datastack */
|
||||||
BOUNDED_BLOCK *cs_region;
|
BOUNDED_BLOCK *data_region;
|
||||||
CELL callframe;
|
/* current callstack top pointer */
|
||||||
struct _STACKS *next;
|
CELL call;
|
||||||
|
/* saved contents of cs register on entry to callback */
|
||||||
|
CELL call_save;
|
||||||
|
/* memory region holding current callstack */
|
||||||
|
BOUNDED_BLOCK *call_region;
|
||||||
|
/* saved callframe on entry to callback */
|
||||||
|
CELL callframe;
|
||||||
|
/* saved catchstack on entry to callback */
|
||||||
|
CELL catch_save;
|
||||||
|
/* error handler longjmp buffer */
|
||||||
|
JMP_BUF toplevel;
|
||||||
|
|
||||||
|
struct _STACKS *next;
|
||||||
} STACKS;
|
} STACKS;
|
||||||
|
|
||||||
STACKS *stack_chain;
|
STACKS *stack_chain;
|
||||||
|
|
||||||
CELL ds_size, cs_size;
|
CELL ds_size, cs_size;
|
||||||
|
|
||||||
#define ds_bot ((CELL)(stack_chain->ds_region->start))
|
#define ds_bot ((CELL)(stack_chain->data_region->start))
|
||||||
#define cs_bot ((CELL)(stack_chain->cs_region->start))
|
#define cs_bot ((CELL)(stack_chain->call_region->start))
|
||||||
|
|
||||||
#define STACK_UNDERFLOW(stack,region) ((stack) + CELLS < (region)->start)
|
#define STACK_UNDERFLOW(stack,region) ((stack) + CELLS < (region)->start)
|
||||||
#define STACK_OVERFLOW(stack,region) ((stack) + CELLS >= (region)->start + (region)->size)
|
#define STACK_OVERFLOW(stack,region) ((stack) + CELLS >= (region)->start + (region)->size)
|
||||||
|
|
Loading…
Reference in New Issue