Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
5 changes: 5 additions & 0 deletions src/mono/mono/mini/aot-compiler.c
Original file line number Diff line number Diff line change
Expand Up @@ -7301,6 +7301,7 @@ encode_patch (MonoAotCompile *acfg, MonoJumpInfo *patch_info, guint8 *buf, guint
encode_field_info (acfg, patch_info->data.field, p, &p);
break;
case MONO_PATCH_INFO_INTERRUPTION_REQUEST_FLAG:
case MONO_PATCH_INFO_LLVMONLY_DO_UNWIND_FLAG:
break;
case MONO_PATCH_INFO_PROFILER_ALLOCATION_COUNT:
case MONO_PATCH_INFO_PROFILER_CLAUSE_COUNT:
Expand Down Expand Up @@ -14586,6 +14587,10 @@ add_preinit_got_slots (MonoAotCompile *acfg)
ji->type = MONO_PATCH_INFO_GC_SAFE_POINT_FLAG;
add_preinit_slot (acfg, ji);

ji = (MonoJumpInfo *)mono_mempool_alloc0 (acfg->mempool, sizeof (MonoJumpInfo));
ji->type = MONO_PATCH_INFO_LLVMONLY_DO_UNWIND_FLAG;
add_preinit_slot (acfg, ji);

if (!acfg->aot_opts.llvm_only) {
for (i = 0; i < TLS_KEY_NUM; i++) {
ji = (MonoJumpInfo *)mono_mempool_alloc0 (acfg->mempool, sizeof (MonoJumpInfo));
Expand Down
1 change: 1 addition & 0 deletions src/mono/mono/mini/aot-runtime.c
Original file line number Diff line number Diff line change
Expand Up @@ -3969,6 +3969,7 @@ decode_patch (MonoAotModule *aot_module, MonoMemPool *mp, MonoJumpInfo *ji, guin
case MONO_PATCH_INFO_GC_NURSERY_BITS:
case MONO_PATCH_INFO_PROFILER_ALLOCATION_COUNT:
case MONO_PATCH_INFO_PROFILER_CLAUSE_COUNT:
case MONO_PATCH_INFO_LLVMONLY_DO_UNWIND_FLAG:
break;
case MONO_PATCH_INFO_SPECIFIC_TRAMPOLINE_LAZY_FETCH_ADDR:
ji->data.uindex = decode_value (p, &p);
Expand Down
59 changes: 41 additions & 18 deletions src/mono/mono/mini/interp/interp.c
Original file line number Diff line number Diff line change
Expand Up @@ -446,12 +446,10 @@ interp_free_context (gpointer ctx)
g_free (context);
}

/* Continue unwinding if there is an exception that needs to be handled in an AOTed frame above us */
static void
check_pending_unwind (ThreadContext *context)
static gboolean
need_native_unwind (ThreadContext *context)
{
if (context->has_resume_state && !context->handler_frame)
mono_llvm_cpp_throw_exception ();
return context->has_resume_state && !context->handler_frame;
}

void
Expand Down Expand Up @@ -2101,7 +2099,7 @@ interp_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObject
* EH processing will continue when control returns to the interpreter.
*/
if (mono_aot_mode == MONO_AOT_MODE_LLVMONLY_INTERP)
mono_llvm_cpp_throw_exception ();
mono_llvm_start_native_unwind ();
return NULL;
}
// The return value is at the bottom of the stack
Expand Down Expand Up @@ -2199,12 +2197,18 @@ interp_entry (InterpEntryData *data)
if (rmethod->needs_thread_attach)
mono_threads_detach_coop (orig_domain, &attach_cookie);

check_pending_unwind (context);
if (need_native_unwind (context)) {
mono_llvm_start_native_unwind ();
return;
}

if (mono_llvm_only) {
if (context->has_resume_state)
if (context->has_resume_state) {
/* The exception will be handled in a frame above us */
mono_llvm_cpp_throw_exception ();
mono_llvm_start_native_unwind ();
// FIXME: Set dummy return value ?
return;
}
} else {
g_assert (!context->has_resume_state);
}
Expand Down Expand Up @@ -2357,7 +2361,7 @@ typedef struct {
MonoFtnDesc ftndesc;
} JitCallCbData;

/* Callback called by mono_llvm_cpp_catch_exception () */
/* Callback called by mono_llvm_catch_exception () */
static void
jit_call_cb (gpointer arg)
{
Expand Down Expand Up @@ -2713,7 +2717,7 @@ do_jit_call (ThreadContext *context, stackval *ret_sp, stackval *sp, InterpFrame

if (mono_aot_mode == MONO_AOT_MODE_LLVMONLY_INTERP) {
/* Catch the exception thrown by the native code using a try-catch */
mono_llvm_cpp_catch_exception (jit_call_cb, &cb_data, &thrown);
mono_llvm_catch_exception (jit_call_cb, &cb_data, &thrown);
} else {
jit_call_cb (&cb_data);
}
Expand Down Expand Up @@ -3080,7 +3084,10 @@ interp_entry_from_trampoline (gpointer ccontext_untyped, gpointer rmethod_untype
if (rmethod->needs_thread_attach)
mono_threads_detach_coop (orig_domain, &attach_cookie);

check_pending_unwind (context);
if (need_native_unwind (context)) {
mono_llvm_start_native_unwind ();
return;
}

/* Write back the return value */
/* 'frame' is still valid */
Expand Down Expand Up @@ -7962,7 +7969,10 @@ interp_run_finally (StackFrameInfo *frame, int clause_index)
iframe->next_free = next_free;
iframe->state.ip = state_ip;

check_pending_unwind (context);
if (need_native_unwind (context)) {
mono_llvm_start_native_unwind ();
return TRUE;
}

if (context->has_resume_state) {
return TRUE;
Expand Down Expand Up @@ -8015,7 +8025,10 @@ interp_run_filter (StackFrameInfo *frame, MonoException *ex, int clause_index, g

context->stack_pointer = (guchar*)child_frame.stack;

check_pending_unwind (context);
if (need_native_unwind (context)) {
mono_llvm_start_native_unwind ();
return TRUE;
}

/* ENDFILTER stores the result into child_frame->retval */
return retval.data.i ? TRUE : FALSE;
Expand Down Expand Up @@ -8159,7 +8172,10 @@ interp_run_clause_with_il_state (gpointer il_state_ptr, int clause_index, MonoOb
memset (sp, 0, (guint8*)context->stack_pointer - (guint8*)sp);
context->stack_pointer = (guchar*)sp;

check_pending_unwind (context);
if (need_native_unwind (context)) {
mono_llvm_start_native_unwind ();
return FALSE;
}

return context->has_resume_state;
}
Expand Down Expand Up @@ -8739,7 +8755,12 @@ mono_jiterp_ld_delegate_method_ptr (gpointer *destination, MonoDelegate **source
MONO_ALWAYS_INLINE void
mono_jiterp_check_pending_unwind (ThreadContext *context)
{
return check_pending_unwind (context);
if (need_native_unwind (context)) {
// FIXME: Caller needs to check this
if (mono_opt_llvm_emulate_unwind)
g_assert_not_reached ();
mono_llvm_start_native_unwind ();
}
}

MONO_ALWAYS_INLINE void *
Expand Down Expand Up @@ -8804,9 +8825,11 @@ mono_jiterp_interp_entry (JiterpEntryData *_data, void *res)
mono_jiterp_check_pending_unwind (header.context);

if (mono_llvm_only) {
if (header.context->has_resume_state)
if (header.context->has_resume_state) {
/* The exception will be handled in a frame above us */
mono_llvm_cpp_throw_exception ();
mono_llvm_start_native_unwind ();
return;
}
} else {
g_assert (!header.context->has_resume_state);
}
Expand Down
2 changes: 2 additions & 0 deletions src/mono/mono/mini/llvm-runtime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@

extern "C" {

extern void mono_wasm_print_stack_trace (void);

// Only called by C functions or LLVM IR generated by Mono cross compiler.
// 'mono_llvm_cpp_throw_exception': function assumed not to throw an exception but does. The function is extern "C" and /EHc was specified.
MONO_DISABLE_WARNING(4297)
Expand Down
89 changes: 84 additions & 5 deletions src/mono/mono/mini/mini-exceptions.c
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@
#include "mini-llvm.h"
#include "aot-runtime.h"
#include "mini-runtime.h"
#include "llvm-runtime.h"
#include "interp/interp.h"

#ifdef ENABLE_LLVM
Expand Down Expand Up @@ -117,6 +118,14 @@ static gpointer throw_corlib_exception_func;

static MonoFtnPtrEHCallback ftnptr_eh_callback;

/*
* Global flag signaling whenever native unwinding is in progress.
* Accessed directly from AOTed code.
* When set, native code should return to their caller until the unwinding
* is finished.
*/
int mono_llvmonly_do_unwind_flag;

static void mono_walk_stack_full (MonoJitStackWalk func, MonoContext *start_ctx, MonoJitTlsData *jit_tls, MonoLMF *lmf, MonoUnwindOptions unwind_options, gpointer user_data, gboolean crash_context);
static void mono_raise_exception_with_ctx (MonoException *exc, MonoContext *ctx);
static void mono_runtime_walk_stack_with_ctx (MonoJitStackWalk func, MonoContext *start_ctx, MonoUnwindOptions unwind_options, void *user_data);
Expand Down Expand Up @@ -3431,7 +3440,7 @@ mini_llvmonly_throw_exception (MonoObject *ex)
llvmonly_setup_exception (ex, FALSE);

/* Unwind back to either an AOTed frame or to the interpreter */
mono_llvm_cpp_throw_exception ();
mono_llvm_start_native_unwind ();
}

void
Expand All @@ -3445,7 +3454,8 @@ mini_llvmonly_rethrow_exception (MonoObject *ex)

mono_handle_exception_internal (&ctx, ex, FALSE, &out_ji);

mono_llvm_cpp_throw_exception ();
/* Unwind back to either an AOTed frame or to the interpreter */
mono_llvm_start_native_unwind ();
}

void
Expand Down Expand Up @@ -3520,11 +3530,16 @@ mini_llvmonly_resume_exception_il_state (MonoLMF *lmf, gpointer info)
MonoMethodILState *il_state = (MonoMethodILState *)info;
MonoJitTlsData *jit_tls = mono_get_jit_tls ();

#ifdef HOST_WASM
//mono_wasm_print_stack_trace ();
#endif

//print_lmf_chain (lmf);

if (jit_tls->resume_state.il_state != il_state) {
/* Call from an AOT method which doesn't catch this exception, continue unwinding */
mono_llvm_cpp_throw_exception ();
mono_llvm_start_native_unwind ();
return;
}
jit_tls->resume_state.il_state = NULL;

Expand All @@ -3537,9 +3552,11 @@ mini_llvmonly_resume_exception_il_state (MonoLMF *lmf, gpointer info)

int clause_index = jit_tls->resume_state.clause_index;
gboolean r = mini_get_interp_callbacks ()->run_clause_with_il_state (il_state, clause_index, ex_obj, NULL);
if (r)
if (r) {
/* Another exception thrown, continue unwinding */
mono_llvm_cpp_throw_exception ();
mono_llvm_start_native_unwind ();
return;
}
}

/*
Expand Down Expand Up @@ -3630,3 +3647,65 @@ mono_debug_personality (void)
g_assert_not_reached ();
}
#endif

/*
* mono_llvm_catch_exception:
*
* Call CB(ARG), catching native exceptions.
* Set OUT_THROW to true if a native exceptions was thrown.
*/
void
mono_llvm_catch_exception (MonoLLVMInvokeCallback cb, gpointer arg, gboolean *out_thrown)
{
*out_thrown = FALSE;

if (mono_opt_llvm_emulate_unwind) {
#ifdef DISABLE_THREADS
// FIXME: The flag needs to be thread local
g_assert_not_reached ();
#endif
// FIXME:
//g_assert (!mono_llvmonly_do_unwind_flag);
mono_llvmonly_do_unwind_flag = FALSE;
cb (arg);
if (mono_llvmonly_do_unwind_flag) {
mono_llvmonly_do_unwind_flag = FALSE;
*out_thrown = TRUE;
}
} else {
mono_llvm_cpp_catch_exception (cb, arg, out_thrown);
}
}

/*
* mono_llvm_start_native_unwind:
*
* Start native unwinding.
* This will either throw a c++ exception or set a flag.
* If this returns, the caller should manually unwind by
* returning to its caller.
*/
void
mono_llvm_start_native_unwind (void)
{
if (mono_opt_llvm_emulate_unwind) {
g_assert (!mono_llvmonly_do_unwind_flag);
mono_llvmonly_do_unwind_flag = TRUE;
} else {
mono_llvm_cpp_throw_exception ();
}
}

/*
* mono_llvm_stop_native_unwind:
*
* Stop native unwinding.
*/
void
mono_llvm_stop_native_unwind (void)
{
if (mono_opt_llvm_emulate_unwind) {
g_assert (mono_llvmonly_do_unwind_flag);
mono_llvmonly_do_unwind_flag = FALSE;
}
}
Loading