[mono][wasm] Avoid AOTing methods with clauses, use the interpreter instead. (#52883)
authorZoltan Varga <vargaz@gmail.com>
Mon, 7 Jun 2021 23:02:04 +0000 (19:02 -0400)
committerGitHub <noreply@github.com>
Mon, 7 Jun 2021 23:02:04 +0000 (19:02 -0400)
src/libraries/Microsoft.VisualBasic.Core/tests/FileSystemTests.cs
src/mono/mono/mini/aot-compiler.c
src/mono/mono/mini/aot-runtime.c
src/mono/mono/mini/aot-runtime.h
src/mono/mono/mini/interp/interp.c
src/mono/mono/mini/interp/transform.c
src/mono/mono/mini/method-to-ir.c
src/mono/mono/mini/mini-exceptions.c
src/mono/mono/mini/mini-runtime.c

index b3428a8..1ce0984 100644 (file)
@@ -182,6 +182,7 @@ namespace Microsoft.VisualBasic.Tests
         //   public static OpenMode FileAttr(int FileNumber){ throw null; }
 
         [Fact]
+        [ActiveIssue("https://github.com/dotnet/runtime/issues/53815", typeof(PlatformDetection), nameof(PlatformDetection.IsBrowser), nameof(PlatformDetection.IsMonoAOT))]
         public void FileClose()
         {
             int fileNumber = FileSystem.FreeFile();
@@ -376,6 +377,7 @@ namespace Microsoft.VisualBasic.Tests
         }
 
         [Fact]
+        [ActiveIssue("https://github.com/dotnet/runtime/issues/53815", typeof(PlatformDetection), nameof(PlatformDetection.IsBrowser), nameof(PlatformDetection.IsMonoAOT))]
         public void FileOpen()
         {
             // OpenMode.Append:
@@ -706,6 +708,7 @@ namespace Microsoft.VisualBasic.Tests
         //   public static void WriteLine(int FileNumber, params object[] Output) { }
 
         [Fact]
+        [ActiveIssue("https://github.com/dotnet/runtime/issues/53815", typeof(PlatformDetection), nameof(PlatformDetection.IsBrowser), nameof(PlatformDetection.IsMonoAOT))]
         public void Write_ArgumentException()
         {
             int fileNumber = FileSystem.FreeFile();
index d4fe08b..358c4e6 100644 (file)
@@ -6983,6 +6983,8 @@ emit_method_info (MonoAotCompile *acfg, MonoCompile *cfg)
                flags |= MONO_AOT_METHOD_FLAG_HAS_PATCHES;
        if (needs_ctx && ctx)
                flags |= MONO_AOT_METHOD_FLAG_HAS_CTX;
+       if (cfg->interp_entry_only)
+               flags |= MONO_AOT_METHOD_FLAG_INTERP_ENTRY_ONLY;
        /* Saved into another table so it can be accessed without having access to this data */
        cfg->aot_method_flags = flags;
 
index 5454871..6a18164 100644 (file)
@@ -4190,7 +4190,7 @@ load_method (MonoAotModule *amodule, MonoImage *image, MonoMethod *method, guint
        if (mono_llvm_only) {
                guint8 flags = amodule->method_flags_table [method_index];
                /* The caller needs to looks this up, but its hard to do without constructing the full MonoJitInfo, so save it here */
-               if (flags & MONO_AOT_METHOD_FLAG_GSHAREDVT_VARIABLE) {
+               if (flags & (MONO_AOT_METHOD_FLAG_GSHAREDVT_VARIABLE | MONO_AOT_METHOD_FLAG_INTERP_ENTRY_ONLY)) {
                        mono_aot_lock ();
                        if (!code_to_method_flags)
                                code_to_method_flags = g_hash_table_new (NULL, NULL);
index 862e74e..af40e8b 100644 (file)
@@ -82,7 +82,8 @@ typedef enum {
        MONO_AOT_METHOD_FLAG_HAS_CCTOR = 1,
        MONO_AOT_METHOD_FLAG_GSHAREDVT_VARIABLE = 2,
        MONO_AOT_METHOD_FLAG_HAS_PATCHES = 4,
-       MONO_AOT_METHOD_FLAG_HAS_CTX = 8
+       MONO_AOT_METHOD_FLAG_HAS_CTX = 8,
+       MONO_AOT_METHOD_FLAG_INTERP_ENTRY_ONLY = 16,
 } MonoAotMethodFlags;
 
 typedef enum {
index 2b92e7f..7bd5558 100644 (file)
@@ -959,7 +959,6 @@ interp_throw (ThreadContext *context, MonoException *ex, InterpFrame *frame, con
        ERROR_DECL (error);
        MonoLMFExt ext;
 
-       interp_push_lmf (&ext, frame);
        /*
         * When explicitly throwing exception we pass the ip of the instruction that throws the exception.
         * Offset the subtraction from interp_frame_get_ip, so we don't end up in prev instruction.
@@ -985,21 +984,11 @@ interp_throw (ThreadContext *context, MonoException *ex, InterpFrame *frame, con
         * Since ctx.ip is 0, this will start unwinding from the LMF frame
         * pushed above, which points to our frames.
         */
-       HandleExceptionCbData cb_data = { ex, &ctx };
-       if (mono_aot_mode == MONO_AOT_MODE_LLVMONLY_INTERP) {
-               gboolean thrown = FALSE;
-               /*
-                * If the exception is uncaught in interpreter code, mono_handle_exception_internal () will rethrow it.
-                * Catch and rethrow it here again so we can pop the LMF.
-                */
-               mono_llvm_cpp_catch_exception (handle_exception_cb, &cb_data, &thrown);
-               if (thrown) {
-                       interp_pop_lmf (&ext);
-                       mono_llvm_rethrow_exception ((MonoObject*)ex);
-               }
-       } else {
-               handle_exception_cb (&cb_data);
-       }
+       interp_push_lmf (&ext, frame);
+
+       mono_handle_exception (&ctx, (MonoObject*)ex);
+
+       interp_pop_lmf (&ext);
 
        if (MONO_CONTEXT_GET_IP (&ctx) != 0) {
                /* We need to unwind into non-interpreter code */
@@ -1007,8 +996,6 @@ interp_throw (ThreadContext *context, MonoException *ex, InterpFrame *frame, con
                g_assert_not_reached ();
        }
 
-       interp_pop_lmf (&ext);
-
        g_assert (context->has_resume_state);
 }
 
@@ -1982,7 +1969,6 @@ interp_entry (InterpEntryData *data)
 
        context->stack_pointer = (guchar*)sp;
 
-       g_assert (!context->has_resume_state);
        g_assert (!context->safepoint_frame);
 
        if (rmethod->needs_thread_attach)
@@ -1990,6 +1976,7 @@ interp_entry (InterpEntryData *data)
 
        if (mono_llvm_only) {
                if (context->has_resume_state)
+                       /* The exception will be handled in a frame above us */
                        mono_llvm_reraise_exception ((MonoException*)mono_gchandle_get_target_internal (context->exc_gchandle));
        } else {
                g_assert (!context->has_resume_state);
@@ -2313,7 +2300,7 @@ init_jit_call_info (InterpMethod *rmethod, MonoError *error)
 }
 
 static MONO_NEVER_INLINE void
-do_jit_call (stackval *ret_sp, stackval *sp, InterpFrame *frame, InterpMethod *rmethod, MonoError *error)
+do_jit_call (ThreadContext *context, stackval *ret_sp, stackval *sp, InterpFrame *frame, InterpMethod *rmethod, MonoError *error)
 {
        MonoLMFExt ext;
        JitCallInfo *cinfo;
@@ -2370,8 +2357,14 @@ do_jit_call (stackval *ret_sp, stackval *sp, InterpFrame *frame, InterpMethod *r
        }
        interp_pop_lmf (&ext);
        if (thrown) {
+               if (context->has_resume_state)
+                       /*
+                        * This happens when interp_entry calls mono_llvm_reraise_exception ().
+                        */
+                       return;
                MonoObject *obj = mono_llvm_load_exception ();
                g_assert (obj);
+               mono_llvm_clear_exception ();
                mono_error_set_exception_instance (error, (MonoException*)obj);
                return;
        }
@@ -3536,7 +3529,7 @@ main_loop:
                        } else if (code_type == IMETHOD_CODE_COMPILED) {
                                frame->state.ip = ip;
                                error_init_reuse (error);
-                               do_jit_call ((stackval*)(locals + return_offset), (stackval*)(locals + call_args_offset), frame, cmethod, error);
+                               do_jit_call (context, (stackval*)(locals + return_offset), (stackval*)(locals + call_args_offset), frame, cmethod, error);
                                if (!is_ok (error)) {
                                        MonoException *ex = mono_error_convert_to_exception (error);
                                        THROW_EX (ex, ip);
@@ -3631,7 +3624,7 @@ call:
                        error_init_reuse (error);
                        /* for calls, have ip pointing at the start of next instruction */
                        frame->state.ip = ip + 4;
-                       do_jit_call ((stackval*)(locals + ip [1]), (stackval*)(locals + ip [2]), frame, rmethod, error);
+                       do_jit_call (context, (stackval*)(locals + ip [1]), (stackval*)(locals + ip [2]), frame, rmethod, error);
                        if (!is_ok (error)) {
                                MonoException *ex = mono_error_convert_to_exception (error);
                                THROW_EX (ex, ip);
@@ -3649,7 +3642,7 @@ call:
                        error_init_reuse (error);
 
                        frame->state.ip = ip + 6;
-                       do_jit_call ((stackval*)(locals + ip [1]), frame, rmethod, error);
+                       do_jit_call (context, (stackval*)(locals + ip [1]), frame, rmethod, error);
                        if (!is_ok (error)) {
                                MonoException *ex = mono_error_convert_to_exception (error);
                                THROW_EX (ex, ip);
index f6a710f..a042e56 100644 (file)
@@ -27,6 +27,7 @@
 
 #include <mono/mini/mini.h>
 #include <mono/mini/mini-runtime.h>
+#include <mono/mini/aot-runtime.h>
 
 #include "mintops.h"
 #include "interp-internals.h"
@@ -1145,11 +1146,18 @@ mono_interp_jit_call_supported (MonoMethod *method, MonoMethodSignature *sig)
        if (method->wrapper_type != MONO_WRAPPER_NONE)
                return FALSE;
 
+       if (method->flags & METHOD_ATTRIBUTE_REQSECOBJ)
+               /* Used to mark methods containing StackCrawlMark locals */
+               return FALSE;
+
        if (mono_aot_only && m_class_get_image (method->klass)->aot_module && !(method->iflags & METHOD_IMPL_ATTRIBUTE_SYNCHRONIZED)) {
                ERROR_DECL (error);
-               gpointer addr = mono_jit_compile_method_jit_only (method, error);
-               if (addr && is_ok (error))
-                       return TRUE;
+               gpointer addr = mono_aot_get_method (method, error);
+               if (addr && is_ok (error)) {
+                       MonoAotMethodFlags flags = mono_aot_get_method_flags (addr);
+                       if (!(flags & MONO_AOT_METHOD_FLAG_INTERP_ENTRY_ONLY))
+                               return TRUE;
+               }
        }
 
        for (l = mono_interp_jit_classes; l; l = l->next) {
index 39f7706..dc22f3e 100644 (file)
@@ -6498,11 +6498,8 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
        }
 
        if (cfg->llvm_only && cfg->interp && cfg->method == method) {
-               for (int i = 0; i < header->num_clauses; ++i) {
-                       MonoExceptionClause *clause = &header->clauses [i];
-                       if (clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY && clause->flags != MONO_EXCEPTION_CLAUSE_FAULT && clause->flags != MONO_EXCEPTION_CLAUSE_NONE)
-                               cfg->interp_entry_only = TRUE;
-               }
+               if (!cfg->method->wrapper_type && header->num_clauses)
+                       cfg->interp_entry_only = TRUE;
 
                if (cfg->interp_entry_only)
                        emit_llvmonly_interp_entry (cfg, header);
index ecaf46f..9ed2ad7 100644 (file)
@@ -2183,7 +2183,8 @@ typedef enum {
  * return \c MONO_FIRST_PASS_CALLBACK_TO_NATIVE).
  */
 static MonoFirstPassResult
-handle_exception_first_pass (MonoContext *ctx, MonoObject *obj, gint32 *out_filter_idx, MonoJitInfo **out_ji, MonoJitInfo **out_prev_ji, MonoObject *non_exception, StackFrameInfo *catch_frame, gboolean *last_mono_wrapper_runtime_invoke)
+handle_exception_first_pass (MonoContext *ctx, MonoObject *obj, gint32 *out_filter_idx, MonoJitInfo **out_ji, MonoJitInfo **out_prev_ji,
+                                                        MonoObject *non_exception, StackFrameInfo *catch_frame, gboolean *last_mono_wrapper_runtime_invoke, gboolean enable_trace)
 {
        ERROR_DECL (error);
        MonoDomain *domain = mono_domain_get ();
@@ -2281,12 +2282,6 @@ handle_exception_first_pass (MonoContext *ctx, MonoObject *obj, gint32 *out_filt
                        *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:
@@ -2405,12 +2400,22 @@ handle_exception_first_pass (MonoContext *ctx, MonoObject *obj, gint32 *out_filt
                                                jit_tls->orig_ex_ctx_set = FALSE;
                                        }
 
+                                       if (enable_trace) {
+                                               char *name = mono_method_get_full_name (method);
+                                               g_print ("[%p:] EXCEPTION running filter clause %d in '%s'.\n", (void*)(gsize)mono_native_thread_id_get (), i, name);
+                                               g_free (name);
+                                       }
+
                                        if (ji->is_interp) {
                                                /* The filter ends where the exception handler starts */
                                                filtered = mini_get_interp_callbacks ()->run_filter (&frame, (MonoException*)ex_obj, i, ei->data.filter, ei->handler_start);
                                        } else {
                                                filtered = call_filter (ctx, ei->data.filter);
                                        }
+
+                                       if (enable_trace)
+                                               g_print ("[%p:] EXCEPTION filter result: %d\n", (void*)(gsize)mono_native_thread_id_get (), filtered);
+
                                        mini_get_dbg_callbacks ()->end_exception_filter (mono_ex, ctx, &initial_ctx);
                                        if (filtered && out_filter_idx)
                                                *out_filter_idx = filter_idx;
@@ -2596,6 +2601,8 @@ mono_handle_exception_internal (MonoContext *ctx, MonoObject *obj, gboolean resu
         */
        memcpy (&jit_tls->orig_ex_ctx, ctx, sizeof (MonoContext));
 
+       gboolean enable_trace = FALSE;
+
        if (!resume) {
                MonoContext ctx_cp = *ctx;
                if (mono_trace_is_enabled ()) {
@@ -2631,9 +2638,12 @@ mono_handle_exception_internal (MonoContext *ctx, MonoObject *obj, gboolean resu
                        }
                        g_print ("[%p:] EXCEPTION handling: %s.%s: %s\n", (void*)(gsize)mono_native_thread_id_get (), m_class_get_name_space (mono_object_class (obj)), m_class_get_name (mono_object_class (obj)), msg);
                        g_free (msg);
-                       if (mono_ex && mono_trace_eval_exception (mono_object_class (mono_ex)))
+                       if (mono_ex && mono_trace_eval_exception (mono_object_class (mono_ex))) {
+                               enable_trace = TRUE;
                                mono_print_thread_dump_from_ctx (ctx);
+                       }
                }
+
                jit_tls->orig_ex_ctx_set = TRUE;
                MONO_PROFILER_RAISE (exception_throw, (obj));
                jit_tls->orig_ex_ctx_set = FALSE;
@@ -2642,14 +2652,9 @@ mono_handle_exception_internal (MonoContext *ctx, MonoObject *obj, gboolean resu
 
                StackFrameInfo catch_frame;
                MonoFirstPassResult res;
-               res = handle_exception_first_pass (&ctx_cp, obj, &first_filter_idx, &ji, &prev_ji, non_exception, &catch_frame, &last_mono_wrapper_runtime_invoke);
+               res = handle_exception_first_pass (&ctx_cp, obj, &first_filter_idx, &ji, &prev_ji, non_exception, &catch_frame, &last_mono_wrapper_runtime_invoke, enable_trace);
 
                if (res == MONO_FIRST_PASS_UNHANDLED) {
-                       if (mono_aot_mode == MONO_AOT_MODE_LLVMONLY_INTERP) {
-                               /* Reached the top interpreted frames, but there might be native frames above us */
-                               throw_exception (obj, TRUE);
-                               g_assert_not_reached ();
-                       }
                        if (mini_debug_options.break_on_exc)
                                G_BREAKPOINT ();
                        mini_get_dbg_callbacks ()->handle_exception ((MonoException *)obj, ctx, NULL, NULL);
index 60d0130..9a84d6b 100644 (file)
@@ -3228,6 +3228,10 @@ mono_jit_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoObjec
 
                gboolean use_interp = FALSE;
 
+               if (mono_aot_mode == MONO_AOT_MODE_LLVMONLY_INTERP)
+                       /* The runtime invoke wrappers contain clauses so they are not AOTed */
+                       use_interp = TRUE;
+
                if (callee) {
                        compiled_method = mono_jit_compile_method_jit_only (callee, error);
                        if (!compiled_method) {