Fix gc with exceptions
This commit is contained in:
+15
-103
@@ -3,7 +3,6 @@
|
||||
|
||||
#include "base.h"
|
||||
|
||||
#include <setjmp.h>
|
||||
#include <stdnoreturn.h>
|
||||
|
||||
enum StackFrameKind {
|
||||
@@ -44,13 +43,16 @@ struct _StackFrame {
|
||||
LispVal *args; // arguments of the function call
|
||||
} call;
|
||||
struct {
|
||||
jmp_buf *target;
|
||||
void (*handler)(void *user_ptr);
|
||||
void *user_ptr;
|
||||
void (*cleanup_user_ptr)(void *data);
|
||||
} unwind_protect;
|
||||
struct {
|
||||
jmp_buf *target;
|
||||
LispVal *exceptions; // list of exception symbols to catch
|
||||
size_t datum; // extra value to identify this case
|
||||
bool enabled;
|
||||
void (*handler)(LispVal *name, LispVal *data, void *user_ptr);
|
||||
void *user_ptr;
|
||||
void (*cleanup_user_ptr)(void *data);
|
||||
} handler_bind;
|
||||
struct {
|
||||
LispVal *symbol;
|
||||
@@ -59,44 +61,22 @@ struct _StackFrame {
|
||||
};
|
||||
};
|
||||
|
||||
enum UnwindCause {
|
||||
UNWIND_NORMAL,
|
||||
UNWIND_EXCEPTION,
|
||||
};
|
||||
|
||||
struct UnwindInformation {
|
||||
bool set;
|
||||
enum UnwindCause cause;
|
||||
union {
|
||||
StackFrame *target;
|
||||
struct {
|
||||
LispVal *name;
|
||||
LispVal *data;
|
||||
StackFrame *handler_frame;
|
||||
} exception;
|
||||
};
|
||||
};
|
||||
|
||||
struct LispStack {
|
||||
size_t max_depth;
|
||||
size_t depth;
|
||||
StackFrame *frames;
|
||||
|
||||
struct UnwindInformation unwind_info;
|
||||
};
|
||||
|
||||
// ONLY APPLIES TO THE CALLING THREAD
|
||||
static ALWAYS_INLINE StackFrame *OBJECT_LOWEST_LOCAL_REFERENCE(LispVal *val) {
|
||||
assert(OBJECTP(val));
|
||||
LispObject *obj = val;
|
||||
return tss_get(obj->gc.lowest_local_ref);
|
||||
return ((LispObject *) val)->gc.lowest_local_ref;
|
||||
}
|
||||
|
||||
static ALWAYS_INLINE void SET_OBJECT_LOWEST_LOCAL_REFERENCE(LispVal *val,
|
||||
StackFrame *frame) {
|
||||
assert(OBJECTP(val));
|
||||
LispObject *obj = val;
|
||||
tss_set(obj->gc.lowest_local_ref, frame);
|
||||
((LispObject *) val)->gc.lowest_local_ref = frame;
|
||||
}
|
||||
|
||||
extern struct LispStack the_stack;
|
||||
@@ -111,32 +91,6 @@ static ALWAYS_INLINE StackFrame *LISP_STACK_REF(void) {
|
||||
return &the_stack.frames[the_stack.depth - 1];
|
||||
}
|
||||
|
||||
static ALWAYS_INLINE void CLEAR_EXCEPTION(void) {
|
||||
the_stack.unwind_info.set = false;
|
||||
}
|
||||
|
||||
static ALWAYS_INLINE bool EXCEPTION_SET_P(void) {
|
||||
return the_stack.unwind_info.set;
|
||||
}
|
||||
|
||||
static ALWAYS_INLINE LispVal *EXCEPTION_NAME(void) {
|
||||
assert(the_stack.unwind_info.set
|
||||
&& the_stack.unwind_info.cause == UNWIND_EXCEPTION);
|
||||
return the_stack.unwind_info.exception.name;
|
||||
}
|
||||
|
||||
static ALWAYS_INLINE LispVal *EXCEPTION_DATA(void) {
|
||||
assert(the_stack.unwind_info.set
|
||||
&& the_stack.unwind_info.cause == UNWIND_EXCEPTION);
|
||||
return the_stack.unwind_info.exception.data;
|
||||
}
|
||||
|
||||
static ALWAYS_INLINE StackFrame *EXCEPTION_HANDLER_FRAME(void) {
|
||||
assert(the_stack.unwind_info.set
|
||||
&& the_stack.unwind_info.cause == UNWIND_EXCEPTION);
|
||||
return the_stack.unwind_info.exception.handler_frame;
|
||||
}
|
||||
|
||||
// functions
|
||||
void push_call_frame(LispVal *name, LispVal *args);
|
||||
// replace the args in the top stack frame with ARGS and mark them as evaluated
|
||||
@@ -145,10 +99,15 @@ void set_stack_evaluated_args(StackFrame *restrict ref, LispVal *fobj,
|
||||
LispVal *args);
|
||||
|
||||
// unwind protect
|
||||
void push_unwind_protect_frame(jmp_buf *buf);
|
||||
void push_unwind_protect_frame(void (*handler)(void *user_ptr), void *user_ptr,
|
||||
void (*cleanup_user_ptr)(void *data));
|
||||
|
||||
// handler bind
|
||||
bool *push_handler_bind_frame(jmp_buf *buf, LispVal *exceptions, size_t datum);
|
||||
void push_handler_bind_frame(LispVal *exceptions,
|
||||
void (*handler)(LispVal *name, LispVal *data,
|
||||
void *user_ptr),
|
||||
void *user_ptr,
|
||||
void (*cleanup_user_ptr)(void *data));
|
||||
|
||||
// local references
|
||||
void push_local_reference_frame(void);
|
||||
@@ -177,7 +136,6 @@ static ALWAYS_INLINE LispVal *UNWIND_AND_RETURN(StackFrame *frame,
|
||||
unwind_to(frame);
|
||||
return val;
|
||||
}
|
||||
noreturn void continue_unwinding(void);
|
||||
|
||||
noreturn void lisp_signal(LispVal *name, LispVal *data);
|
||||
|
||||
@@ -186,52 +144,6 @@ noreturn void lisp_signal(LispVal *name, LispVal *data);
|
||||
*/
|
||||
DECLARE_FUNCTION(backtrace, (void) );
|
||||
|
||||
#define UNWIND_PROTECT(body, cleanup) \
|
||||
{ \
|
||||
jmp_buf _internal_jb; \
|
||||
if (setjmp(_internal_jb) == 0) { \
|
||||
push_unwind_protect_frame(&_internal_jb); \
|
||||
StackFrame *_internal_target = LISP_STACK_REF(); \
|
||||
{body}; \
|
||||
unwind_to(_internal_target); \
|
||||
} else { \
|
||||
{cleanup}; \
|
||||
continue_unwinding(); \
|
||||
} \
|
||||
};
|
||||
|
||||
#define HANDLER_BIND1(exceptions, body, handler) \
|
||||
{ \
|
||||
jmp_buf _internal_jb; \
|
||||
StackFrame *_internal_target = LISP_STACK_REF(); \
|
||||
bool *enabled; \
|
||||
if (setjmp(_internal_jb) == 0) { \
|
||||
enabled = push_handler_bind_frame(&_internal_jb, (exceptions), 0); \
|
||||
{body}; \
|
||||
unwind_to(_internal_target); \
|
||||
} else { \
|
||||
*enabled = false; \
|
||||
{handler}; \
|
||||
*enabled = true; \
|
||||
continue_unwinding(); \
|
||||
} \
|
||||
};
|
||||
|
||||
#define CONDITION_CASE1(exceptions, body, handler) \
|
||||
{ \
|
||||
jmp_buf _internal_jb; \
|
||||
StackFrame *_internal_target = LISP_STACK_REF(); \
|
||||
if (setjmp(_internal_jb) == 0) { \
|
||||
push_handler_bind_frame(&_internal_jb, (exceptions), 0); \
|
||||
{body}; \
|
||||
unwind_to(_internal_target); \
|
||||
} else { \
|
||||
unwind_to(_internal_target); \
|
||||
{handler}; \
|
||||
CLEAR_EXCEPTION(); \
|
||||
} \
|
||||
};
|
||||
|
||||
DECLARE_SYMBOL(excessive_lisp_nesting_error);
|
||||
MAKE_CONDITION_CLASS(excessive_lisp_nesting_error);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user