[mono] Stop first pass exception handling when exiting the interpreter in llvmonly...
authorZoltan Varga <vargaz@gmail.com>
Tue, 23 Mar 2021 06:27:57 +0000 (02:27 -0400)
committerGitHub <noreply@github.com>
Tue, 23 Mar 2021 06:27:57 +0000 (02:27 -0400)
* [mono] Add a FRAME_TYPE_INTERP_ENTRY frame type to the unwinder, it marks the location where execution transfers
to the interpreter.

* [mono] Stop first pass exception handling when exiting the interpreter in llvmonly mode.

Otherwise, you could end up with the following situation:
- [1] interpreted frame
- [2] AOTed frame catching the exception
- [3] interpreted frame catching the same exception

The EH code would think frame [3] caught the exception, setting up interpreter state for
resuming there, but frame [2] would catch the exception, so the exception state in
the interpreter would not be cleared, leading to an assert in interp_entry ().

Fixes https://github.com/dotnet/runtime/issues/47334.

src/mono/mono/metadata/loader.c
src/mono/mono/mini/mini-exceptions.c
src/mono/mono/utils/mono-stack-unwinding.h

index 1b473b0..dc531e1 100644 (file)
@@ -1670,6 +1670,7 @@ stack_walk_adapter (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer data)
        case FRAME_TYPE_TRAMPOLINE:
        case FRAME_TYPE_INTERP_TO_MANAGED:
        case FRAME_TYPE_INTERP_TO_MANAGED_WITH_CTX:
+       case FRAME_TYPE_INTERP_ENTRY:
                return FALSE;
        case FRAME_TYPE_MANAGED:
        case FRAME_TYPE_INTERP:
index b1ea490..060da0b 100644 (file)
@@ -762,7 +762,7 @@ unwinder_unwind_frame (Unwinder *unwinder,
                }
 
                if (!unwinder->in_interp)
-                       return unwinder_unwind_frame (unwinder, jit_tls, prev_ji, ctx, new_ctx, trace, lmf, save_locations, frame);
+                       frame->type = FRAME_TYPE_INTERP_ENTRY;
                return TRUE;
        } else {
                gboolean res = mono_find_jit_info_ext (jit_tls, prev_ji, ctx, new_ctx, trace, lmf,
@@ -1874,6 +1874,7 @@ ves_icall_get_frame_info (gint32 skip, MonoBoolean need_file_info,
                        case FRAME_TYPE_TRAMPOLINE:
                        case FRAME_TYPE_INTERP_TO_MANAGED:
                        case FRAME_TYPE_INTERP_TO_MANAGED_WITH_CTX:
+                       case FRAME_TYPE_INTERP_ENTRY:
                                continue;
                        case FRAME_TYPE_INTERP:
                        case FRAME_TYPE_MANAGED:
@@ -2280,6 +2281,15 @@ handle_exception_first_pass (MonoContext *ctx, MonoObject *obj, gint32 *out_filt
                case FRAME_TYPE_INTERP_TO_MANAGED_WITH_CTX:
                        *ctx = new_ctx;
                        continue;
+               case FRAME_TYPE_INTERP_ENTRY:
+                       if (mono_aot_mode == MONO_AOT_MODE_LLVMONLY_INTERP)
+                               /*
+                                * There might be AOTed frames above the intepreted frames which can handle the exception,
+                                * so stop first pass, the caller will rethrow the exception, starting the process again.
+                                */
+                               return MONO_FIRST_PASS_UNHANDLED;
+                       *ctx = new_ctx;
+                       continue;
                case FRAME_TYPE_INTERP:
                case FRAME_TYPE_MANAGED:
                        break;
@@ -2734,6 +2744,7 @@ mono_handle_exception_internal (MonoContext *ctx, MonoObject *obj, gboolean resu
                        case FRAME_TYPE_MANAGED_TO_NATIVE:
                        case FRAME_TYPE_TRAMPOLINE:
                        case FRAME_TYPE_INTERP_TO_MANAGED_WITH_CTX:
+                       case FRAME_TYPE_INTERP_ENTRY:
                                *ctx = new_ctx;
                                continue;
                        case FRAME_TYPE_INTERP_TO_MANAGED:
index 91506b2..15335fc 100644 (file)
@@ -28,7 +28,9 @@ typedef enum {
        FRAME_TYPE_INTERP_TO_MANAGED = 5,
        /* same, but with MonoContext */
        FRAME_TYPE_INTERP_TO_MANAGED_WITH_CTX = 6,
-       FRAME_TYPE_NUM = 7
+       /* Frame for transitioning to interpreted code */
+       FRAME_TYPE_INTERP_ENTRY = 7,
+       FRAME_TYPE_NUM = 8
 } MonoStackFrameType;
 
 typedef enum {