Added 'depth' counter to stack frames. The idea is two-fold:
1. You can limit runaway recursion by binding a symbol *max_stack_depth* in the environment 2. You can limit the number of backtrace frames printed. However, neither of these have been implemented yet.
This commit is contained in:
parent
72a8bc09e0
commit
2536e76617
7 changed files with 140 additions and 79 deletions
|
|
@ -96,6 +96,9 @@ void maybe_bind_init_symbols( ) {
|
||||||
if ( nilp( privileged_keyword_payload ) ) {
|
if ( nilp( privileged_keyword_payload ) ) {
|
||||||
privileged_keyword_payload = c_string_to_lisp_keyword( L"payload" );
|
privileged_keyword_payload = c_string_to_lisp_keyword( L"payload" );
|
||||||
}
|
}
|
||||||
|
if ( nilp( privileged_keyword_cause)) {
|
||||||
|
privileged_keyword_cause = c_string_to_lisp_keyword(L"cause");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void free_init_symbols( ) {
|
void free_init_symbols( ) {
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,12 @@ struct cons_pointer privileged_keyword_location = NIL;
|
||||||
*/
|
*/
|
||||||
struct cons_pointer privileged_keyword_payload = NIL;
|
struct cons_pointer privileged_keyword_payload = NIL;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Keywords used when constructing exceptions: `:payload`. Instantiated in
|
||||||
|
* `init.c`, q.v.
|
||||||
|
*/
|
||||||
|
struct cons_pointer privileged_keyword_cause = NIL;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* True if the value of the tag on the cell at this `pointer` is this `value`,
|
* True if the value of the tag on the cell at this `pointer` is this `value`,
|
||||||
* or, if the tag of the cell is `VECP`, if the value of the tag of the
|
* or, if the tag of the cell is `VECP`, if the value of the tag of the
|
||||||
|
|
|
||||||
|
|
@ -68,6 +68,12 @@ extern struct cons_pointer privileged_keyword_location;
|
||||||
*/
|
*/
|
||||||
extern struct cons_pointer privileged_keyword_payload;
|
extern struct cons_pointer privileged_keyword_payload;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Keywords used when constructing exceptions: `:cause`. Instantiated in
|
||||||
|
* `init.c`.
|
||||||
|
*/
|
||||||
|
extern struct cons_pointer privileged_keyword_cause;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* An unallocated cell on the free list - should never be encountered by a Lisp
|
* An unallocated cell on the free list - should never be encountered by a Lisp
|
||||||
* function.
|
* function.
|
||||||
|
|
@ -456,6 +462,8 @@ struct stack_frame {
|
||||||
struct cons_pointer function;
|
struct cons_pointer function;
|
||||||
/** the number of arguments provided. */
|
/** the number of arguments provided. */
|
||||||
int args;
|
int args;
|
||||||
|
/** the depth of the stack below this frame */
|
||||||
|
int depth;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -98,6 +98,8 @@ struct cons_pointer make_empty_frame( struct cons_pointer previous ) {
|
||||||
for ( int i = 0; i < args_in_frame; i++ ) {
|
for ( int i = 0; i < args_in_frame; i++ ) {
|
||||||
frame->arg[i] = NIL;
|
frame->arg[i] = NIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
frame->depth = (nilp(previous)) ? 0 : (get_stack_frame(previous))->depth + 1;
|
||||||
}
|
}
|
||||||
debug_print( L"Leaving make_empty_frame\n", DEBUG_ALLOC );
|
debug_print( L"Leaving make_empty_frame\n", DEBUG_ALLOC );
|
||||||
debug_dump_object( result, DEBUG_ALLOC );
|
debug_dump_object( result, DEBUG_ALLOC );
|
||||||
|
|
@ -285,7 +287,8 @@ void dump_frame( URL_FILE *output, struct cons_pointer frame_pointer ) {
|
||||||
struct stack_frame *frame = get_stack_frame( frame_pointer );
|
struct stack_frame *frame = get_stack_frame( frame_pointer );
|
||||||
|
|
||||||
if ( frame != NULL ) {
|
if ( frame != NULL ) {
|
||||||
url_fwprintf( output, L"Stack frame with %d arguments:\n",
|
url_fwprintf( output, L"Stack frame %d with %d arguments:\n",
|
||||||
|
frame->depth;
|
||||||
frame->args );
|
frame->args );
|
||||||
dump_frame_context( output, frame_pointer, 4 );
|
dump_frame_context( output, frame_pointer, 4 );
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -316,7 +316,9 @@ struct cons_pointer search_store( struct cons_pointer key,
|
||||||
return_key ? "key" : "value" );
|
return_key ? "key" : "value" );
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if ( symbolp( key ) || keywordp( key ) ) {
|
switch ( get_tag_value( key) ) {
|
||||||
|
case SYMBOLTV:
|
||||||
|
case KEYTV:
|
||||||
struct cons_space_object *store_cell = &pointer2cell( store );
|
struct cons_space_object *store_cell = &pointer2cell( store );
|
||||||
|
|
||||||
switch ( get_tag_value( store ) ) {
|
switch ( get_tag_value( store ) ) {
|
||||||
|
|
@ -389,8 +391,17 @@ struct cons_pointer search_store( struct cons_pointer key,
|
||||||
c_type( store ) ), NIL );
|
c_type( store ) ), NIL );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else {
|
break;
|
||||||
// failing with key type NIL here (?). Probably worth dumping the stack?
|
case EXCEPTIONTV:
|
||||||
|
result =
|
||||||
|
throw_exception( c_string_to_lisp_symbol( L"search-store (exception)" ),
|
||||||
|
make_cons
|
||||||
|
( c_string_to_lisp_string
|
||||||
|
( L"Unexpected key type: " ), c_type( key ) ),
|
||||||
|
NIL );
|
||||||
|
|
||||||
|
break;
|
||||||
|
default:
|
||||||
result =
|
result =
|
||||||
throw_exception( c_string_to_lisp_symbol( L"search-store (key)" ),
|
throw_exception( c_string_to_lisp_symbol( L"search-store (key)" ),
|
||||||
make_cons
|
make_cons
|
||||||
|
|
|
||||||
|
|
@ -1329,18 +1329,18 @@ lisp_cond( struct stack_frame *frame, struct cons_pointer frame_pointer,
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Throw an exception.
|
* Throw an exception with a cause.
|
||||||
* `throw_exception` is a misnomer, because it doesn't obey the calling signature of a
|
* `throw_exception` is a misnomer, because it doesn't obey the calling signature of a
|
||||||
* lisp function; but it is nevertheless to be preferred to make_exception. A
|
* lisp function; but it is nevertheless to be preferred to make_exception. A
|
||||||
* real `throw_exception`, which does, will be needed.
|
* real `throw_exception`, which does, will be needed.
|
||||||
* object pointing to it. Then this should become a normal lisp function
|
* object pointing to it. Then this should become a normal lisp function
|
||||||
* which expects a normally bound frame and environment, such that
|
* which expects a normally bound frame and environment, such that
|
||||||
* frame->arg[0] is the message, and frame->arg[1] is the cons-space
|
* frame->arg[0] is the payload, frame->arg[1] is the cause, and frame->arg[2] is the cons-space
|
||||||
* pointer to the frame in which the exception occurred.
|
* pointer to the frame in which the exception occurred.
|
||||||
*/
|
*/
|
||||||
struct cons_pointer
|
struct cons_pointer throw_exception_with_cause( struct cons_pointer location,
|
||||||
throw_exception( struct cons_pointer location,
|
|
||||||
struct cons_pointer message,
|
struct cons_pointer message,
|
||||||
|
struct cons_pointer cause,
|
||||||
struct cons_pointer frame_pointer ) {
|
struct cons_pointer frame_pointer ) {
|
||||||
struct cons_pointer result = NIL;
|
struct cons_pointer result = NIL;
|
||||||
|
|
||||||
|
|
@ -1350,9 +1350,13 @@ throw_exception( struct cons_pointer location,
|
||||||
debug_print( L"` at `", 511 );
|
debug_print( L"` at `", 511 );
|
||||||
debug_print_object( location, 511 );
|
debug_print_object( location, 511 );
|
||||||
debug_print( L"`\n", 511 );
|
debug_print( L"`\n", 511 );
|
||||||
debug_print_object( location, 511 );
|
if (!nilp( cause)) {
|
||||||
|
debug_print( L"\tCaused by: ", 511)
|
||||||
|
;
|
||||||
|
debug_print_object( cause, 511);
|
||||||
|
debug_print( L"`\n", 511 );
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct cons_space_object *cell = &pointer2cell( message );
|
struct cons_space_object *cell = &pointer2cell( message );
|
||||||
|
|
||||||
if ( cell->tag.value == EXCEPTIONTV ) {
|
if ( cell->tag.value == EXCEPTIONTV ) {
|
||||||
|
|
@ -1364,10 +1368,31 @@ throw_exception( struct cons_pointer location,
|
||||||
location ),
|
location ),
|
||||||
make_cons( make_cons
|
make_cons( make_cons
|
||||||
( privileged_keyword_payload,
|
( privileged_keyword_payload,
|
||||||
message ), NIL ) ), frame_pointer );
|
message ),
|
||||||
|
(nilp( cause) ? NIL :
|
||||||
|
make_cons( make_cons( privileged_keyword_cause,
|
||||||
|
cause), NIL)) ) ), frame_pointer );
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Throw an exception.
|
||||||
|
* `throw_exception` is a misnomer, because it doesn't obey the calling signature of a
|
||||||
|
* lisp function; but it is nevertheless to be preferred to make_exception. A
|
||||||
|
* real `throw_exception`, which does, will be needed.
|
||||||
|
* object pointing to it. Then this should become a normal lisp function
|
||||||
|
* which expects a normally bound frame and environment, such that
|
||||||
|
* frame->arg[0] is the payload, frame->arg[1] is the cause, and frame->arg[2] is the cons-space
|
||||||
|
* pointer to the frame in which the exception occurred.
|
||||||
|
*/
|
||||||
|
struct cons_pointer
|
||||||
|
throw_exception( struct cons_pointer location,
|
||||||
|
struct cons_pointer payload,
|
||||||
|
struct cons_pointer frame_pointer ) {
|
||||||
|
return throw_exception_with_cause( location, payload, NIL, frame_pointer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -1393,8 +1418,9 @@ lisp_exception( struct stack_frame *frame, struct cons_pointer frame_pointer,
|
||||||
struct cons_pointer env ) {
|
struct cons_pointer env ) {
|
||||||
struct cons_pointer message = frame->arg[0];
|
struct cons_pointer message = frame->arg[0];
|
||||||
|
|
||||||
return exceptionp( message ) ? message : throw_exception( message,
|
return exceptionp( message ) ? message : throw_exception_with_cause( message,
|
||||||
frame->arg[1],
|
frame->arg[1],
|
||||||
|
frame->arg[2],
|
||||||
frame->previous );
|
frame->previous );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -190,6 +190,10 @@ struct cons_pointer lisp_cond( struct stack_frame *frame,
|
||||||
struct cons_pointer frame_pointer,
|
struct cons_pointer frame_pointer,
|
||||||
struct cons_pointer env );
|
struct cons_pointer env );
|
||||||
|
|
||||||
|
struct cons_pointer throw_exception_with_cause( struct cons_pointer location,
|
||||||
|
struct cons_pointer message,
|
||||||
|
struct cons_pointer cause,
|
||||||
|
struct cons_pointer frame_pointer );
|
||||||
/**
|
/**
|
||||||
* Throw an exception.
|
* Throw an exception.
|
||||||
* `throw_exception` is a misnomer, because it doesn't obey the calling
|
* `throw_exception` is a misnomer, because it doesn't obey the calling
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue