Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Exception stacks #28878

Merged
merged 16 commits into from
Oct 23, 2018
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Exception stack runtime cleanup
* 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
commit 3453c27db9494afd8cc6f89b0ca19222fa64ca35
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