Skip to content

Commit

Permalink
Exception stack runtime cleanup
Browse files Browse the repository at this point in the history
* Use functions rather than macros for exception stack access
* Use standard type check macro
* More clearly document gc rooting of `jl_current_exception()`
  • Loading branch information
c42f committed Oct 14, 2018
1 parent 250571c commit 3453c27
Show file tree
Hide file tree
Showing 4 changed files with 32 additions and 15 deletions.
2 changes: 0 additions & 2 deletions src/jlapi.c
Original file line number Diff line number Diff line change
Expand Up @@ -102,8 +102,6 @@ JL_DLLEXPORT jl_value_t *jl_eval_string(const char *str)
return r;
}

// FIXME: annotating this with JL_GLOBALLY_ROOTED is over optimistic. It's
// rooted by the task which is rooted in the TLS.
JL_DLLEXPORT jl_value_t *jl_current_exception(void) JL_GLOBALLY_ROOTED
{
jl_exc_stack_t *s = jl_get_ptls_states()->current_task->exc_stack;
Expand Down
11 changes: 8 additions & 3 deletions src/julia.h
Original file line number Diff line number Diff line change
Expand Up @@ -1425,9 +1425,14 @@ JL_DLLEXPORT void JL_NORETURN jl_bounds_error_tuple_int(jl_value_t **v,
JL_DLLEXPORT void JL_NORETURN jl_bounds_error_unboxed_int(void *v, jl_value_t *vt, size_t i);
JL_DLLEXPORT void JL_NORETURN jl_bounds_error_ints(jl_value_t *v, size_t *idxs, size_t nidxs);
JL_DLLEXPORT void JL_NORETURN jl_eof_error(void);
// Return the exception currently being handled, or nothing if we are not
// inside the scope of a JL_CATCH. Note that catch scope is determined
// dynamically so this works in functions called from a catch block.

// Return the exception currently being handled, or `jl_nothing`.
//
// The catch scope is determined dynamically so this works in functions called
// from a catch block. The returned value is gc rooted until we exit the
// enclosing JL_CATCH.
// FIXME: Teach the static analyzer about this rather than using
// JL_GLOBALLY_ROOTED which is far too optimistic.
JL_DLLEXPORT jl_value_t *jl_current_exception(void) JL_GLOBALLY_ROOTED;
JL_DLLEXPORT jl_value_t *jl_exception_occurred(void);
JL_DLLEXPORT void jl_exception_clear(void) JL_NOTSAFEPOINT;
Expand Down
31 changes: 23 additions & 8 deletions src/julia_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -660,26 +660,41 @@ JL_DLLEXPORT int jl_is_enter_interpreter_frame(uintptr_t ip);
JL_DLLEXPORT size_t jl_capture_interp_frame(uintptr_t *data, uintptr_t sp, uintptr_t fp, size_t space_remaining);

// Exception stack: a stack of pairs of (exception,raw_backtrace).
// The stack may be traversed and accessed with the macros below.
// The stack may be traversed and accessed with the functions below.
typedef struct _jl_exc_stack_t {
size_t top;
size_t reserved_size;
// Pack all stack entries into a growable buffer to amortize allocation
// across repeated exception handling.
// Layout: [bt_data1... bt_size1 exc1 bt_data2... bt_size2 exc2 ..]
// uintptr_t data[]; // Access with jl_excstk_raw
#define jl_excstk_raw(stack) ((uintptr_t*)((char*)(stack) + sizeof(jl_exc_stack_t)))
} jl_exc_stack_t;

// Stack access
static inline jl_value_t *jl_exc_stack_exception(jl_exc_stack_t *stack JL_PROPAGATES_ROOT,
STATIC_INLINE uintptr_t *jl_excstk_raw(jl_exc_stack_t* stack)
{
return (uintptr_t*)(stack + 1);
}

// Exception stack access
STATIC_INLINE jl_value_t *jl_exc_stack_exception(jl_exc_stack_t *stack JL_PROPAGATES_ROOT,
size_t itr) JL_NOTSAFEPOINT
{
return (jl_value_t*)jl_excstk_raw(stack)[(itr)-1];
return (jl_value_t*)(jl_excstk_raw(stack)[itr-1]);
}
STATIC_INLINE size_t jl_exc_stack_bt_size(jl_exc_stack_t *stack, size_t itr)
{
return jl_excstk_raw(stack)[itr-2];
}
STATIC_INLINE uintptr_t *jl_exc_stack_bt_data(jl_exc_stack_t *stack, size_t itr)
{
return jl_excstk_raw(stack) + itr-2 - jl_exc_stack_bt_size(stack, itr);
}
#define jl_exc_stack_bt_size(stack, itr) ((size_t)jl_excstk_raw(stack)[(itr)-2])
#define jl_exc_stack_bt_data(stack, itr) (jl_excstk_raw(stack) + itr - 2 - jl_excstk_raw(stack)[(itr)-2])
// Exception stack iteration (start at itr=stack->top, stop at itr=0)
#define jl_exc_stack_next(stack, itr) ((itr) - 2 - jl_exc_stack_bt_size(stack,itr))
STATIC_INLINE size_t jl_exc_stack_next(jl_exc_stack_t *stack, size_t itr)
{
return itr-2 - jl_exc_stack_bt_size(stack, itr);
}
// Exception stack manipulation
void jl_reserve_exc_stack(jl_exc_stack_t **stack JL_REQUIRE_ROOTED_SLOT,
size_t reserved_size);
void jl_push_exc_stack(jl_exc_stack_t **stack JL_REQUIRE_ROOTED_SLOT JL_ROOTING_ARGUMENT,
Expand Down
3 changes: 1 addition & 2 deletions src/stackwalk.c
Original file line number Diff line number Diff line change
Expand Up @@ -183,8 +183,7 @@ JL_DLLEXPORT void jl_get_backtrace(jl_array_t **btout, jl_array_t **bt2out)
// interleaved.
JL_DLLEXPORT jl_value_t *jl_get_exc_stack(jl_value_t* task, int include_bt, int max_entries)
{
if (!jl_typeis(task, jl_task_type))
jl_error("Cannot get exception stack from a non-Task type");
JL_TYPECHK(catch_stack, task, task);
jl_array_t *stack = NULL;
jl_array_t *bt = NULL;
jl_array_t *bt2 = NULL;
Expand Down

0 comments on commit 3453c27

Please sign in to comment.