Skip to content

Commit

Permalink
[mono][wasm] Avoid AOTing methods with clauses, use the interpreter i…
Browse files Browse the repository at this point in the history
…nstead. (#52883)
  • Loading branch information
vargaz authored Jun 7, 2021
1 parent 866bf99 commit d173cca
Show file tree
Hide file tree
Showing 9 changed files with 60 additions and 47 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,7 @@ public void EOF()
// 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();
Expand Down Expand Up @@ -376,6 +377,7 @@ public void FileLen()
}

[Fact]
[ActiveIssue("https://github.com/dotnet/runtime/issues/53815", typeof(PlatformDetection), nameof(PlatformDetection.IsBrowser), nameof(PlatformDetection.IsMonoAOT))]
public void FileOpen()
{
// OpenMode.Append:
Expand Down Expand Up @@ -706,6 +708,7 @@ public void Rename()
// 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();
Expand Down
2 changes: 2 additions & 0 deletions src/mono/mono/mini/aot-compiler.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
2 changes: 1 addition & 1 deletion src/mono/mono/mini/aot-runtime.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
3 changes: 2 additions & 1 deletion src/mono/mono/mini/aot-runtime.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
39 changes: 16 additions & 23 deletions src/mono/mono/mini/interp/interp.c
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -985,30 +984,18 @@ 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 */
mono_restore_context (&ctx);
g_assert_not_reached ();
}

interp_pop_lmf (&ext);

g_assert (context->has_resume_state);
}

Expand Down Expand Up @@ -1982,14 +1969,14 @@ 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)
mono_threads_detach_coop (orig_domain, &attach_cookie);

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);
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -3536,7 +3529,7 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs
} 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);
Expand Down Expand Up @@ -3631,7 +3624,7 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs
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);
Expand All @@ -3649,7 +3642,7 @@ interp_exec_method (InterpFrame *frame, ThreadContext *context, FrameClauseArgs
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);
Expand Down
14 changes: 11 additions & 3 deletions src/mono/mono/mini/interp/transform.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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) {
Expand Down
7 changes: 2 additions & 5 deletions src/mono/mono/mini/method-to-ir.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
33 changes: 19 additions & 14 deletions src/mono/mono/mini/mini-exceptions.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 ();
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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 ()) {
Expand Down Expand Up @@ -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;
Expand All @@ -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);
Expand Down
4 changes: 4 additions & 0 deletions src/mono/mono/mini/mini-runtime.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down

0 comments on commit d173cca

Please sign in to comment.