* [mono][wasm] Allow AOTing methods with catch clauses.
This works as follows:
* During EH, when a catch clause is found in an AOTed method, the
EH state is saved into TLS and a c++ exception is thrown.
* The C++ exception is caught by the AOTed method, and the landing
pad code calls mono_llvm_resume_exception_il_state ().
* That call will run the catch clause and the rest of the method
code using the interpreter, storing the possible return value
back into the AOTed method's stack frame.
* After the call, the method skips the rest of its code, and
returns immediately to its caller.
* Fix console bench sample.
* Fix landing pads.
* Fix issues.
* Add support for filter clauses.
* Implement all wasm return conventions.
* Fix arg/local write back.
* Avoid throwing a c++ exception from do_jit_call () so the caller can clean up the interpreter stack.
* Disable AOTing some more assemblies on CI.
* Rename llvmonly EH functions to mini_llvmonly_ for clarity.
* Improve unwinding through interpreter frames.
Instead of throwing a c++ exception from mono_handle_exception ()
when an exception is caught in AOTed code, set context->has_resume_state,
so the intepreter will normally unwind until exiting interpreted code.
Then throw the c++ exception after the call to interp_exec_method ()
to unwind through the runtime code and the AOTed frames
which can't handle the exception.
<Import Project="System.Text.Json.SourceGeneration.Tests.targets" />
+ <ItemGroup Condition="'$(ContinuousIntegrationBuild)' == 'true'">
+ <HighAotMemoryUsageAssembly Include="System.Text.Json.SourceGeneration.Roslyn3.11.Tests.dll"/>
+ </ItemGroup>
+
<ItemGroup>
<ProjectReference Include="..\..\gen\System.Text.Json.SourceGeneration.Roslyn3.11.csproj" OutputItemType="Analyzer" ReferenceOutputAssembly="false" />
<ProjectReference Include="..\System.Text.Json.SourceGeneration.TestLibrary\System.Text.Json.TestLibrary.Roslyn3.11.csproj" />
<Project Sdk="Microsoft.NET.Sdk">
- <ItemGroup>
+ <ItemGroup Condition="'$(ContinuousIntegrationBuild)' == 'true'">
<HighAotMemoryUsageAssembly Include="Microsoft.CodeAnalysis.CSharp.dll" />
+ <HighAotMemoryUsageAssembly Include="System.Text.Json.SourceGeneration.Roslyn4.0.Tests.dll"/>
</ItemGroup>
<Import Project="System.Text.Json.SourceGeneration.Tests.targets" />
<PropertyGroup>
<DefineConstants Condition="$([MSBuild]::GetTargetFrameworkIdentifier('$(TargetFramework)')) == '.NETCoreApp'">$(DefineConstants);BUILDING_INBOX_LIBRARY</DefineConstants>
</PropertyGroup>
+
+ <ItemGroup Condition="'$(ContinuousIntegrationBuild)' == 'true'">
+ <HighAotMemoryUsageAssembly Include="System.Text.Json.Tests.dll"/>
+ </ItemGroup>
+
<ItemGroup>
<Compile Include="$(CommonTestPath)System\IO\WrappedMemoryStream.cs" Link="CommonTest\System\IO\WrappedMemoryStream.cs" />
<Compile Include="..\Common\CollectionTests\CollectionTests.AsyncEnumerable.cs" Link="CommonTest\System\Text\Json\Tests\Serialization\CollectionTests\CollectionTests.AsyncEnumerable.cs" />
MONO_JIT_ICALL (mini_llvmonly_throw_aot_failed_exception) \
MONO_JIT_ICALL (mini_llvmonly_pop_lmf) \
MONO_JIT_ICALL (mini_llvmonly_interp_entry_gsharedvt) \
+MONO_JIT_ICALL (mini_llvmonly_throw_exception) \
+MONO_JIT_ICALL (mini_llvmonly_rethrow_exception) \
+MONO_JIT_ICALL (mini_llvmonly_throw_corlib_exception) \
+MONO_JIT_ICALL (mini_llvmonly_resume_exception) \
+MONO_JIT_ICALL (mini_llvmonly_resume_exception_il_state) \
+MONO_JIT_ICALL (mini_llvmonly_load_exception) \
+MONO_JIT_ICALL (mini_llvmonly_clear_exception) \
+MONO_JIT_ICALL (mini_llvmonly_match_exception) \
MONO_JIT_ICALL (mono_amd64_resume_unwind) \
MONO_JIT_ICALL (mono_amd64_start_gsharedvt_call) \
MONO_JIT_ICALL (mono_amd64_throw_corlib_exception) \
MONO_JIT_ICALL (mono_ldtoken_wrapper_generic_shared) \
MONO_JIT_ICALL (mono_ldvirtfn) \
MONO_JIT_ICALL (mono_ldvirtfn_gshared) \
-MONO_JIT_ICALL (mono_llvm_clear_exception) \
-MONO_JIT_ICALL (mono_llvm_load_exception) \
-MONO_JIT_ICALL (mono_llvm_match_exception) \
-MONO_JIT_ICALL (mono_llvm_resume_exception) \
MONO_JIT_ICALL (mono_llvm_resume_unwind_trampoline) \
-MONO_JIT_ICALL (mono_llvm_rethrow_exception) \
MONO_JIT_ICALL (mono_llvm_rethrow_exception_trampoline) \
MONO_JIT_ICALL (mono_llvm_set_unhandled_exception_handler) \
-MONO_JIT_ICALL (mono_llvm_throw_corlib_exception) \
MONO_JIT_ICALL (mono_llvm_throw_corlib_exception_abs_trampoline) \
MONO_JIT_ICALL (mono_llvm_throw_corlib_exception_trampoline) \
-MONO_JIT_ICALL (mono_llvm_throw_exception) \
MONO_JIT_ICALL (mono_llvm_throw_exception_trampoline) \
MONO_JIT_ICALL (mono_llvmonly_init_delegate) \
MONO_JIT_ICALL (mono_llvmonly_init_delegate_virtual) \
static const MonoJitICallId preinited_jit_icalls [] = {
MONO_JIT_ICALL_mini_llvm_init_method,
MONO_JIT_ICALL_mini_llvmonly_throw_nullref_exception,
- MONO_JIT_ICALL_mono_llvm_throw_corlib_exception,
+ MONO_JIT_ICALL_mini_llvmonly_throw_corlib_exception,
MONO_JIT_ICALL_mono_threads_state_poll,
MONO_JIT_ICALL_mini_llvmonly_init_vtable_slot,
MONO_JIT_ICALL_mono_helper_ldstr_mscorlib,
#ifndef __MONO_EE_H__
#define __MONO_EE_H__
-#define MONO_EE_API_VERSION 0x15
+#define MONO_EE_API_VERSION 0x16
typedef struct _MonoInterpStackIter MonoInterpStackIter;
MONO_EE_CALLBACK (void, get_resume_state, (const MonoJitTlsData *jit_tls, gboolean *has_resume_state, MonoInterpFrameHandle *interp_frame, gpointer *handler_ip)) \
MONO_EE_CALLBACK (gboolean, run_finally, (StackFrameInfo *frame, int clause_index, gpointer handler_ip, gpointer handler_ip_end)) \
MONO_EE_CALLBACK (gboolean, run_filter, (StackFrameInfo *frame, MonoException *ex, int clause_index, gpointer handler_ip, gpointer handler_ip_end)) \
- MONO_EE_CALLBACK (gboolean, run_finally_with_il_state, (gpointer il_state, int clause_index, gpointer handler_ip, gpointer handler_ip_end)) \
+ MONO_EE_CALLBACK (gboolean, run_clause_with_il_state, (gpointer il_state, int clause_index, gpointer handler_ip, gpointer handler_ip_end, MonoObject *ex, gboolean *filtered, MonoExceptionEnum clause_type)) \
MONO_EE_CALLBACK (void, frame_iter_init, (MonoInterpStackIter *iter, gpointer interp_exit_data)) \
MONO_EE_CALLBACK (gboolean, frame_iter_next, (MonoInterpStackIter *iter, StackFrameInfo *frame)) \
MONO_EE_CALLBACK (MonoJitInfo*, find_jit_info, (MonoMethod *method)) \
}
static gboolean
-stub_run_finally_with_il_state (gpointer il_state, int clause_index, gpointer handler_ip, gpointer handler_ip_end)
+stub_run_clause_with_il_state (gpointer il_state, int clause_index, gpointer handler_ip, gpointer handler_ip_end, MonoObject *ex,
+ gboolean *filtered, MonoExceptionEnum clause_type)
{
g_assert_not_reached ();
}
/* Lets interpreter know it has to resume execution after EH */
gboolean has_resume_state;
/* Frame to resume execution at */
+ /* Can be NULL if the exception is caught in an AOTed frame */
InterpFrame *handler_frame;
/* IP to resume execution at */
const guint16 *handler_ip;
* frame further down the stack.
*/
const guint16 *end_at_ip;
- /* When exiting this clause we also exit the frame */
- int exit_clause;
/* Frame that is executing this clause */
InterpFrame *exec_frame;
};
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)
+{
+ if (context->has_resume_state && !context->handler_frame)
+ mono_llvm_cpp_throw_exception ();
+}
+
void
mono_interp_error_cleanup (MonoError* error)
{
context->stack_pointer = (guchar*)sp;
+ check_pending_unwind (context);
+
if (context->has_resume_state) {
/*
* This can happen on wasm where native frames cannot be skipped during EH.
if (rmethod->needs_thread_attach)
mono_threads_detach_coop (orig_domain, &attach_cookie);
+ check_pending_unwind (context);
+
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));
+ mono_llvm_cpp_throw_exception ();
} else {
g_assert (!context->has_resume_state);
}
* This happens when interp_entry calls mono_llvm_reraise_exception ().
*/
return;
- MonoObject *obj = mono_llvm_load_exception ();
+ MonoJitTlsData *jit_tls = mono_get_jit_tls ();
+ if (jit_tls->resume_state.il_state) {
+ /*
+ * This c++ exception is going to be caught by an AOTed frame above us.
+ * We can't rethrow here, since that will skip the cleanup of the
+ * interpreter stack space etc. So instruct the interpreter to unwind.
+ */
+ context->has_resume_state = TRUE;
+ context->handler_frame = NULL;
+ return;
+ }
+ MonoObject *obj = mini_llvmonly_load_exception ();
g_assert (obj);
- mono_llvm_clear_exception ();
+ mini_llvmonly_clear_exception ();
mono_error_set_exception_instance (error, (MonoException*)obj);
return;
}
if (rmethod->needs_thread_attach)
mono_threads_detach_coop (orig_domain, &attach_cookie);
+ check_pending_unwind (context);
+
/* Write back the return value */
/* 'frame' is still valid */
mono_arch_set_native_call_context_ret (ccontext, &frame, sig, retp);
InterpMethod *imethod = mono_interp_get_imethod (method, error);
return_val_if_nok (error, NULL);
- mono_interp_transform_method (imethod, get_context (), error);
- return_val_if_nok (error, NULL);
+ if (!imethod->transformed) {
+ mono_interp_transform_method (imethod, get_context (), error);
+ return_val_if_nok (error, NULL);
+ }
return imethod->jinfo;
}
* interp_set_resume_state:
*
* Set the state the interpeter will continue to execute from after execution returns to the interpreter.
+ * If INTERP_FRAME is NULL, that means the exception is caught in an AOTed frame and the interpreter needs to
+ * unwind back to AOT code.
*/
static void
interp_set_resume_state (MonoJitTlsData *jit_tls, MonoObject *ex, MonoJitExceptionInfo *ei, MonoInterpFrameHandle interp_frame, gpointer handler_ip)
mono_gchandle_free_internal (context->exc_gchandle);
context->exc_gchandle = mono_gchandle_new_internal ((MonoObject*)ex, FALSE);
/* Ditto */
- if (ei)
- *(MonoObject**)(frame_locals (context->handler_frame) + ei->exvar_offset) = ex;
+ if (context->handler_frame) {
+ if (ei)
+ *(MonoObject**)(frame_locals (context->handler_frame) + ei->exvar_offset) = ex;
+ }
context->handler_ip = (const guint16*)handler_ip;
}
memset (&clause_args, 0, sizeof (FrameClauseArgs));
clause_args.start_with_ip = (const guint16*)handler_ip;
clause_args.end_at_ip = (const guint16*)handler_ip_end;
- clause_args.exit_clause = clause_index;
clause_args.exec_frame = iframe;
state_ip = iframe->state.ip;
iframe->next_free = next_free;
iframe->state.ip = state_ip;
+
+ check_pending_unwind (context);
+
if (context->has_resume_state) {
return TRUE;
} else {
context->stack_pointer = (guchar*)child_frame.stack;
+ check_pending_unwind (context);
+
/* ENDFILTER stores the result into child_frame->retval */
return retval.data.i ? TRUE : FALSE;
}
+/* Returns TRUE if there is a pending exception */
static gboolean
-interp_run_finally_with_il_state (gpointer il_state_ptr, int clause_index, gpointer handler_ip, gpointer handler_ip_end)
+interp_run_clause_with_il_state (gpointer il_state_ptr, int clause_index, gpointer handler_ip, gpointer handler_ip_end,
+ MonoObject *ex, gboolean *filtered, MonoExceptionEnum clause_type)
{
MonoMethodILState *il_state = (MonoMethodILState*)il_state_ptr;
MonoMethodSignature *sig;
ThreadContext *context = get_context ();
+ stackval *orig_sp;
stackval *sp, *sp_args;
InterpMethod *imethod;
FrameClauseArgs clause_args;
ERROR_DECL (error);
- // FIXME: Optimize this ? Its only used during EH
-
sig = mono_method_signature_internal (il_state->method);
g_assert (sig);
imethod = mono_interp_get_imethod (il_state->method, error);
mono_error_assert_ok (error);
- sp_args = sp = (stackval*)context->stack_pointer;
+ orig_sp = sp_args = sp = (stackval*)context->stack_pointer;
+
+ gpointer ret_addr = NULL;
int findex = 0;
+ if (sig->ret->type != MONO_TYPE_VOID) {
+ ret_addr = il_state->data [findex];
+ findex ++;
+ }
if (sig->hasthis) {
if (il_state->data [findex])
sp_args->data.p = *(gpointer*)il_state->data [findex];
if (header->num_locals)
memset (frame_locals (&frame) + imethod->local_offsets [0], 0, imethod->locals_size);
/* Copy locals from il_state */
- int locals_start = sig->hasthis + sig->param_count;
+ int locals_start = findex;
for (int i = 0; i < header->num_locals; ++i) {
if (il_state->data [locals_start + i])
stackval_from_data (header->locals [i], (stackval*)(frame_locals (&frame) + imethod->local_offsets [i]), il_state->data [locals_start + i], FALSE);
memset (&clause_args, 0, sizeof (FrameClauseArgs));
clause_args.start_with_ip = (const guint16*)handler_ip;
- clause_args.end_at_ip = (const guint16*)handler_ip_end;
- clause_args.exit_clause = clause_index;
+ if (clause_type == MONO_EXCEPTION_CLAUSE_NONE || clause_type == MONO_EXCEPTION_CLAUSE_FILTER)
+ clause_args.end_at_ip = (const guint16*)clause_args.start_with_ip + 0xffffff;
+ else
+ clause_args.end_at_ip = (const guint16*)handler_ip_end;
clause_args.exec_frame = &frame;
- // this informs MINT_ENDFINALLY to return to EH
- *(guint16**)(frame_locals (&frame) + imethod->clause_data_offsets [clause_index]) = NULL;
+ if (clause_type == MONO_EXCEPTION_CLAUSE_NONE || clause_type == MONO_EXCEPTION_CLAUSE_FILTER)
+ *(MonoObject**)(frame_locals (&frame) + imethod->jinfo->clauses [clause_index].exvar_offset) = ex;
+ else
+ // this informs MINT_ENDFINALLY to return to EH
+ *(guint16**)(frame_locals (&frame) + imethod->clause_data_offsets [clause_index]) = NULL;
+
+ /* Set in mono_handle_exception () */
+ context->has_resume_state = FALSE;
interp_exec_method (&frame, context, &clause_args);
/* Write back args */
sp_args = sp;
findex = 0;
+ if (sig->ret->type != MONO_TYPE_VOID)
+ findex ++;
if (sig->hasthis) {
// FIXME: This
sp_args++;
findex ++;
}
- findex = sig->hasthis ? 1 : 0;
for (int i = 0; i < sig->param_count; ++i) {
if (il_state->data [findex]) {
int size = stackval_to_data (sig->params [i], sp_args, il_state->data [findex], FALSE);
}
mono_metadata_free_mh (header);
- // FIXME: Restore stack ?
- if (context->has_resume_state)
- return TRUE;
- else
- return FALSE;
+ if (clause_type == MONO_EXCEPTION_CLAUSE_NONE && ret_addr) {
+ stackval_to_data (sig->ret, frame.retval, ret_addr, FALSE);
+ } else if (clause_type == MONO_EXCEPTION_CLAUSE_FILTER) {
+ g_assert (filtered);
+ *filtered = frame.retval->data.i;
+ }
+
+ memset (orig_sp, 0, (guint8*)context->stack_pointer - (guint8*)orig_sp);
+ context->stack_pointer = (guchar*)orig_sp;
+
+ check_pending_unwind (context);
+
+ return context->has_resume_state;
}
typedef struct {
gpointer result = resolve_vcall (this_obj->vtable, slot, imt_method, out_arg, TRUE, error);
if (!is_ok (error)) {
MonoException *ex = mono_error_convert_to_exception (error);
- mono_llvm_throw_exception ((MonoObject*)ex);
+ mini_llvmonly_throw_exception ((MonoObject*)ex);
}
return result;
}
gpointer addr = resolve_vcall (vtable, slot, NULL, &arg, TRUE, error);
if (!is_ok (error)) {
MonoException *ex = mono_error_convert_to_exception (error);
- mono_llvm_throw_exception ((MonoObject*)ex);
+ mini_llvmonly_throw_exception ((MonoObject*)ex);
}
ftndesc = m_class_alloc0 (vtable->klass, sizeof (MonoFtnDesc));
mini_resolve_imt_method (vt, imt + imt_slot, generic_virtual, &m, &aot_addr, &need_rgctx_tramp, &variant_iface, error);
if (!is_ok (error)) {
MonoException *ex = mono_error_convert_to_exception (error);
- mono_llvm_throw_exception ((MonoObject*)ex);
+ mini_llvmonly_throw_exception ((MonoObject*)ex);
}
if (m_class_is_valuetype (vt->klass))
gpointer addr = resolve_iface_call (this_obj, imt_slot, imt_method, out_arg, TRUE, error);
if (!is_ok (error)) {
MonoException *ex = mono_error_convert_to_exception (error);
- mono_llvm_throw_exception ((MonoObject*)ex);
+ mini_llvmonly_throw_exception ((MonoObject*)ex);
}
if (!gsharedvt_imt [imt_slot]) {
if (ex) {
/* Its okay to raise in llvmonly mode */
if (mono_llvm_only) {
- mono_llvm_throw_exception ((MonoObject*)ex);
+ mini_llvmonly_throw_exception ((MonoObject*)ex);
} else {
mono_set_pending_exception (ex);
}
guint32 ex_token_index = m_class_get_type_token (klass) - MONO_TOKEN_TYPE_DEF;
- mono_llvm_throw_corlib_exception (ex_token_index);
+ mini_llvmonly_throw_corlib_exception (ex_token_index);
}
void
char *msg = g_strdup_printf ("AOT Compilation failed for method '%s'.", name);
MonoException *ex = mono_get_exception_execution_engine (msg);
g_free (msg);
- mono_llvm_throw_exception ((MonoObject*)ex);
+ mini_llvmonly_throw_exception ((MonoObject*)ex);
}
/*
G_EXTERN_C void mini_llvmonly_interp_entry_gsharedvt (gpointer imethod, gpointer res, gpointer *args);
+/* These are implemented in mini-exceptions.c */
+G_EXTERN_C void mini_llvmonly_throw_exception (MonoObject *ex);
+G_EXTERN_C void mini_llvmonly_rethrow_exception (MonoObject *ex);
+G_EXTERN_C void mini_llvmonly_throw_corlib_exception (guint32 ex_token_index);
+G_EXTERN_C void mini_llvmonly_resume_exception (void);
+G_EXTERN_C void mini_llvmonly_resume_exception_il_state (MonoLMF *lmf, gpointer info);
+G_EXTERN_C MonoObject *mini_llvmonly_load_exception (void);
+G_EXTERN_C void mini_llvmonly_clear_exception (void);
+G_EXTERN_C gint32 mini_llvmonly_match_exception (MonoJitInfo *jinfo, guint32 region_start, guint32 region_end, gpointer rgctx, MonoObject *this_obj);
+
#endif
for (int i = 0; i < header->num_clauses; ++i) {
MonoExceptionClause *clause = &header->clauses [i];
/* Finally clauses are checked after the remove_finally pass */
+
if (clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY)
cfg->interp_entry_only = TRUE;
}
start_new_bblock = 0;
MonoOpcodeEnum il_op; il_op = MonoOpcodeEnum_Invalid;
+ emit_set_deopt_il_offset (cfg, ip - cfg->cil_start);
+
for (guchar *next_ip = ip; ip < end; ip = next_ip) {
MonoOpcodeEnum previous_il_op = il_op;
const guchar *tmp_ip = ip;
#include "trace.h"
#include "seq-points.h"
#include "llvm-runtime.h"
+#include "llvmonly-runtime.h"
#include "mini-llvm.h"
#include "aot-runtime.h"
#include "mini-runtime.h"
static void mono_uninstall_current_handler_block_guard (void);
static gboolean mono_exception_walk_trace_internal (MonoException *ex, MonoExceptionFrameWalk func, gpointer user_data);
static void throw_exception (MonoObject *ex, gboolean rethrow);
+static void llvmonly_raise_exception (MonoException *e);
+static void llvmonly_reraise_exception (MonoException *e);
static gboolean
first_managed (MonoStackFrameInfo *frame, MonoContext *ctx, gpointer addr)
cbs.mono_walk_stack_with_state = mono_walk_stack_with_state;
if (mono_llvm_only) {
- cbs.mono_raise_exception = mono_llvm_raise_exception;
- cbs.mono_reraise_exception = mono_llvm_reraise_exception;
+ cbs.mono_raise_exception = llvmonly_raise_exception;
+ cbs.mono_reraise_exception = llvmonly_reraise_exception;
} else {
cbs.mono_raise_exception = (void (*)(MonoException *))mono_get_throw_exception ();
cbs.mono_reraise_exception = (void (*)(MonoException *))mono_get_rethrow_exception ();
frame->type = FRAME_TYPE_JIT_ENTRY;
} else if (ext->kind == MONO_LMFEXT_IL_STATE) {
frame->type = FRAME_TYPE_IL_STATE;
+ frame->managed = TRUE;
frame->method = ext->il_state->method;
frame->actual_method = ext->il_state->method;
frame->il_state = ext->il_state;
frame_count ++;
method = jinfo_get_method (ji);
- //printf ("M: %s %d.\n", mono_method_full_name (method, TRUE), frame_count);
+ //printf ("[%d]: %s.\n", frame_count, mono_method_full_name (method, TRUE));
if (mini_debug_options.reverse_pinvoke_exceptions && method->wrapper_type == MONO_WRAPPER_NATIVE_TO_MANAGED) {
g_error ("A native frame was found while unwinding the stack after an exception.\n"
g_free (name);
}
- if (ji->is_interp) {
+ if (frame.type == FRAME_TYPE_IL_STATE) {
+ if (mono_trace_is_enabled () && mono_trace_eval (method))
+ g_print ("EXCEPTION: filter clause found in AOTed code, running it with the interpreter.\n");
+ gboolean res = mini_get_interp_callbacks ()->run_clause_with_il_state (frame.il_state, i, ei->data.filter, NULL, ex_obj, &filtered, MONO_EXCEPTION_CLAUSE_FILTER);
+ // FIXME:
+ g_assert (!res);
+ } else 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 {
method = jinfo_get_method (ji);
frame_count ++;
- //printf ("M: %s %d.\n", mono_method_full_name (method, TRUE), frame_count);
+ //printf ("[%d] %s.\n", frame_count, mono_method_full_name (method, TRUE));
if (stack_overflow) {
free_stack = (guint8*)(MONO_CONTEXT_GET_SP (ctx)) - (guint8*)(MONO_CONTEXT_GET_SP (&initial_ctx));
mini_set_abort_threshold (&frame);
+ if (frame.type == FRAME_TYPE_IL_STATE) {
+ if (mono_trace_is_enabled () && mono_trace_eval (method))
+ g_print ("EXCEPTION: catch clause found in AOTed code.\n");
+ /*
+ * Save the state needed to execute the catch clause in TLS, then
+ * throw a c++ exception which is going to be caught by AOTed
+ * methods, then execute the clause and the rest of the method
+ * using the interpreter.
+ */
+ jit_tls->resume_state.ex_obj = obj;
+ jit_tls->resume_state.ji = ji;
+ jit_tls->resume_state.clause_index = i;
+ jit_tls->resume_state.il_state = frame.il_state;
+
+ /* Instruct the intepreter to unwind back to AOTed code */
+ mini_get_interp_callbacks ()->set_resume_state (jit_tls, ex_obj, ei, NULL, NULL);
+ }
+
if (in_interp) {
/*
* ctx->pc points into the interpreter, after the call which transitioned to
mini_set_abort_threshold (&frame);
if (frame.type == FRAME_TYPE_IL_STATE) {
if (mono_trace_is_enabled () && mono_trace_eval (method))
- g_print ("EXCEPTION: clause found in AOTed code, running clause with interpreter.\n");
- mini_get_interp_callbacks ()->run_finally_with_il_state (frame.il_state, i, ei->handler_start, ei->data.handler_end);
+ g_print ("EXCEPTION: finally/fault clause found in AOTed code, running it with the interpreter.\n");
+ mini_get_interp_callbacks ()->run_clause_with_il_state (frame.il_state, i, ei->handler_start, ei->data.handler_end, NULL, NULL, MONO_EXCEPTION_CLAUSE_FINALLY);
} else if (in_interp) {
gboolean has_ex = mini_get_interp_callbacks ()->run_finally (&frame, i, ei->handler_start, ei->data.handler_end);
if (has_ex) {
#endif
}
- mono_llvm_cpp_throw_exception ();
+ if (rethrow) {
+ MonoContext ctx;
+ MonoJitInfo *out_ji;
+ memset (&ctx, 0, sizeof (MonoContext));
+
+ mono_handle_exception_internal (&ctx, ex, FALSE, &out_ji);
+ mono_llvm_cpp_throw_exception ();
+ }
}
void
-mono_llvm_throw_exception (MonoObject *ex)
+mini_llvmonly_throw_exception (MonoObject *ex)
{
g_assert (mono_llvm_only);
mono_handle_exception (&ctx, (MonoObject*)ex);
throw_exception (ex, FALSE);
+
+ /* Unwind back to either an AOTed frame or to the interpreter */
+ mono_llvm_cpp_throw_exception ();
}
void
-mono_llvm_rethrow_exception (MonoObject *ex)
+mini_llvmonly_rethrow_exception (MonoObject *ex)
{
throw_exception (ex, TRUE);
}
void
-mono_llvm_raise_exception (MonoException *e)
+mini_llvmonly_throw_corlib_exception (guint32 ex_token_index)
+{
+ guint32 ex_token = MONO_TOKEN_TYPE_DEF | ex_token_index;
+ MonoException *ex;
+
+ ex = mono_exception_from_token (m_class_get_image (mono_defaults.exception_class), ex_token);
+
+ mini_llvmonly_throw_exception ((MonoObject*)ex);
+}
+
+static void
+llvmonly_raise_exception (MonoException *e)
{
- mono_llvm_throw_exception ((MonoObject*)e);
+ mini_llvmonly_throw_exception ((MonoObject*)e);
}
-void
-mono_llvm_reraise_exception (MonoException *e)
+static void
+llvmonly_reraise_exception (MonoException *e)
{
- mono_llvm_rethrow_exception ((MonoObject*)e);
+ mini_llvmonly_rethrow_exception ((MonoObject*)e);
}
+/*
+ * mini_llvmonly_resume_exception:
+ *
+ * Resume exception propagation.
+ */
void
-mono_llvm_throw_corlib_exception (guint32 ex_token_index)
+mini_llvmonly_resume_exception (void)
{
- guint32 ex_token = MONO_TOKEN_TYPE_DEF | ex_token_index;
- MonoException *ex;
+ mono_llvm_cpp_throw_exception ();
+}
- ex = mono_exception_from_token (m_class_get_image (mono_defaults.exception_class), ex_token);
+static G_GNUC_UNUSED void
+print_lmf_chain (MonoLMF *lmf)
+{
+ MonoJitTlsData *jit_tls = mono_get_jit_tls ();
+
+ while (lmf && lmf != jit_tls->first_lmf) {
+ printf ("LMF: %p ", lmf);
+
+ if (((gsize)lmf->previous_lmf) & 2) {
+ MonoLMFExt *ext = (MonoLMFExt*)lmf;
+
+ switch (ext->kind) {
+ case MONO_LMFEXT_DEBUGGER_INVOKE:
+ printf ("dbg invoke");
+ break;
+ case MONO_LMFEXT_INTERP_EXIT:
+ case MONO_LMFEXT_INTERP_EXIT_WITH_CTX:
+ printf ("interp exit");
+ break;
+ case MONO_LMFEXT_JIT_ENTRY:
+ printf ("jit entry");
+ break;
+ case MONO_LMFEXT_IL_STATE:
+ printf ("il state ['%s']", mono_method_get_full_name (ext->il_state->method));
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+ printf ("\n");
- mono_llvm_throw_exception ((MonoObject*)ex);
+ lmf = (MonoLMF *)(((gsize)lmf->previous_lmf) & ~3);
+ }
+ }
}
/*
- * mono_llvm_resume_exception:
+ * mini_llvmonly_resume_exception_il_state:
*
- * Resume exception propagation.
+ * Called from AOTed code to execute catch clauses.
*/
void
-mono_llvm_resume_exception (void)
+mini_llvmonly_resume_exception_il_state (MonoLMF *lmf, gpointer info)
{
- mono_llvm_cpp_throw_exception ();
+ MonoMethodILState *il_state = (MonoMethodILState *)info;
+ MonoJitTlsData *jit_tls = mono_get_jit_tls ();
+
+ //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 ();
+ }
+ jit_tls->resume_state.il_state = NULL;
+
+ /* Pop the LMF frame so the caller doesn't have to do it */
+ mono_set_lmf ((MonoLMF *)(((gsize)lmf->previous_lmf) & ~3));
+
+ MonoJitInfo *ji = jit_tls->resume_state.ji;
+ int clause_index = jit_tls->resume_state.clause_index;
+ MonoJitExceptionInfo *ei = &ji->clauses [clause_index];
+ gboolean r = mini_get_interp_callbacks ()->run_clause_with_il_state (il_state, clause_index, ei->handler_start, NULL, jit_tls->resume_state.ex_obj, NULL, MONO_EXCEPTION_CLAUSE_NONE);
+ if (r)
+ /* Another exception thrown, continue unwinding */
+ mono_llvm_cpp_throw_exception ();
}
/*
- * mono_llvm_load_exception:
+ * mini_llvmonly_load_exception:
*
* Return the currently thrown exception.
*/
MonoObject *
-mono_llvm_load_exception (void)
+mini_llvmonly_load_exception (void)
{
HANDLE_FUNCTION_ENTER ();
ERROR_DECL (error);
}
/*
- * mono_llvm_clear_exception:
+ * mini_llvmonly_clear_exception:
*
* Mark the currently thrown exception as handled.
*/
void
-mono_llvm_clear_exception (void)
+mini_llvmonly_clear_exception (void)
{
MonoJitTlsData *jit_tls = mono_get_jit_tls ();
}
/*
- * mono_llvm_match_exception:
+ * mini_llvmonly_match_exception:
*
* Return the innermost clause containing REGION_START-REGION_END which can handle
* the current exception.
*/
gint32
-mono_llvm_match_exception (MonoJitInfo *jinfo, guint32 region_start, guint32 region_end, gpointer rgctx, MonoObject *this_obj)
+mini_llvmonly_match_exception (MonoJitInfo *jinfo, guint32 region_start, guint32 region_end, gpointer rgctx, MonoObject *this_obj)
{
ERROR_DECL (error);
MonoJitTlsData *jit_tls = mono_get_jit_tls ();
gboolean is_linkonce;
gboolean emit_dummy_arg;
gboolean has_safepoints;
+ gboolean has_catch;
int this_arg_pindex, rgctx_arg_pindex;
LLVMValueRef imt_rgctx_loc;
GHashTable *llvm_types;
int *gc_var_indexes;
LLVMValueRef gc_pin_area;
LLVMValueRef il_state;
+ LLVMValueRef il_state_ret;
} EmitContext;
typedef struct {
MonoExceptionClause *clause;
if (ctx->llvm_only) {
- clause = get_most_deep_clause (cfg, ctx, bb);
-
- if (!ctx->cfg->deopt && clause) {
- g_assert (clause->flags == MONO_EXCEPTION_CLAUSE_NONE || clause->flags == MONO_EXCEPTION_CLAUSE_FINALLY || clause->flags == MONO_EXCEPTION_CLAUSE_FAULT);
+ clause = bb ? get_most_deep_clause (cfg, ctx, bb) : NULL;
+ // FIXME: Use an invoke only for calls inside try-catch blocks
+ if (clause && (!cfg->deopt || ctx->has_catch)) {
/*
* Have to use an invoke instead of a call, branching to the
* handler bblock of the clause containing this bblock.
if (!sig)
sig = LLVMFunctionType1 (LLVMVoidType (), LLVMInt32Type (), FALSE);
- callee = get_callee (ctx, sig, MONO_PATCH_INFO_JIT_ICALL_ADDR, GUINT_TO_POINTER (MONO_JIT_ICALL_mono_llvm_throw_corlib_exception));
+ callee = get_callee (ctx, sig, MONO_PATCH_INFO_JIT_ICALL_ADDR, GUINT_TO_POINTER (MONO_JIT_ICALL_mini_llvmonly_throw_corlib_exception));
args [0] = LLVMConstInt (LLVMInt32Type (), m_class_get_type_token (exc_class) - MONO_TOKEN_TYPE_DEF, FALSE);
emit_call (ctx, bb, &builder, callee, args, 1);
}
if (cfg->deopt) {
LLVMValueRef addr, index [2];
MonoMethodHeader *header = cfg->header;
- int nfields = sig->hasthis + sig->param_count + header->num_locals + 2;
+ int nfields = (sig->ret->type != MONO_TYPE_VOID ? 1 : 0) + sig->hasthis + sig->param_count + header->num_locals + 2;
LLVMTypeRef *types = g_alloca (nfields * sizeof (LLVMTypeRef));
int findex = 0;
/* method */
types [findex ++] = LLVMInt32Type ();
int data_start = findex;
/* data */
+ if (sig->ret->type != MONO_TYPE_VOID)
+ types [findex ++] = IntPtrType ();
if (sig->hasthis)
types [findex ++] = IntPtrType ();
for (int i = 0; i < sig->param_count; ++i)
* clauses are supposed to be volatile, so they have an address.
*/
findex = data_start;
+ if (sig->ret->type != MONO_TYPE_VOID) {
+ LLVMTypeRef ret_type = type_to_llvm_type (ctx, sig->ret);
+ ctx->il_state_ret = build_alloca_llvm_type_name (ctx, ret_type, 0, "il_state_ret");
+
+ index [0] = LLVMConstInt (LLVMInt32Type (), 0, FALSE);
+ index [1] = LLVMConstInt (LLVMInt32Type (), findex, FALSE);
+ addr = LLVMBuildGEP (builder, ctx->il_state, index, 2, "");
+ LLVMBuildStore (ctx->builder, ctx->il_state_ret, convert (ctx, addr, LLVMPointerType (LLVMTypeOf (ctx->il_state_ret), 0)));
+ findex ++;
+ }
for (int i = 0; i < sig->hasthis + sig->param_count; ++i) {
LLVMValueRef var_addr = ctx->addresses [cfg->args [i]->dreg];
static void
emit_llvmonly_throw (EmitContext *ctx, MonoBasicBlock *bb, gboolean rethrow, LLVMValueRef exc)
{
- MonoJitICallId icall_id = rethrow ? MONO_JIT_ICALL_mono_llvm_rethrow_exception : MONO_JIT_ICALL_mono_llvm_throw_exception;
+ MonoJitICallId icall_id = rethrow ? MONO_JIT_ICALL_mini_llvmonly_rethrow_exception : MONO_JIT_ICALL_mini_llvmonly_throw_exception;
LLVMValueRef callee = rethrow ? ctx->module->rethrow : ctx->module->throw_icall;
LLVMTypeRef exc_type = type_to_llvm_type (ctx, m_class_get_byval_arg (mono_get_exception_class ()));
static void
emit_resume_eh (EmitContext *ctx, MonoBasicBlock *bb)
{
- const MonoJitICallId icall_id = MONO_JIT_ICALL_mono_llvm_resume_exception;
+ const MonoJitICallId icall_id = MONO_JIT_ICALL_mini_llvmonly_resume_exception;
LLVMValueRef callee;
LLVMTypeRef fun_sig = LLVMFunctionType0 (LLVMVoidType (), FALSE);
static LLVMValueRef
mono_llvm_emit_clear_exception_call (EmitContext *ctx, LLVMBuilderRef builder)
{
- const char *icall_name = "mono_llvm_clear_exception";
- const MonoJitICallId icall_id = MONO_JIT_ICALL_mono_llvm_clear_exception;
+ const MonoJitICallId icall_id = MONO_JIT_ICALL_mini_llvmonly_clear_exception;
LLVMTypeRef call_sig = LLVMFunctionType (LLVMVoidType (), NULL, 0, FALSE);
LLVMValueRef callee = NULL;
if (!callee) {
- if (ctx->cfg->compile_aot) {
- callee = get_callee (ctx, call_sig, MONO_PATCH_INFO_JIT_ICALL_ID, GUINT_TO_POINTER (icall_id));
- } else {
- // FIXME: This is broken.
- callee = LLVMAddFunction (ctx->lmodule, icall_name, call_sig);
- }
+ callee = get_callee (ctx, call_sig, MONO_PATCH_INFO_JIT_ICALL_ID, GUINT_TO_POINTER (icall_id));
}
g_assert (builder && callee);
static LLVMValueRef
mono_llvm_emit_load_exception_call (EmitContext *ctx, LLVMBuilderRef builder)
{
- const char *icall_name = "mono_llvm_load_exception";
- const MonoJitICallId icall_id = MONO_JIT_ICALL_mono_llvm_load_exception;
+ const MonoJitICallId icall_id = MONO_JIT_ICALL_mini_llvmonly_load_exception;
LLVMTypeRef call_sig = LLVMFunctionType (ObjRefType (), NULL, 0, FALSE);
LLVMValueRef callee = NULL;
+ g_assert (ctx->cfg->compile_aot);
+
if (!callee) {
- if (ctx->cfg->compile_aot) {
- callee = get_callee (ctx, call_sig, MONO_PATCH_INFO_JIT_ICALL_ID, GUINT_TO_POINTER (icall_id));
- } else {
- // FIXME: This is broken.
- callee = LLVMAddFunction (ctx->lmodule, icall_name, call_sig);
- }
+ callee = get_callee (ctx, call_sig, MONO_PATCH_INFO_JIT_ICALL_ID, GUINT_TO_POINTER (icall_id));
}
g_assert (builder && callee);
- return LLVMBuildCall (builder, callee, NULL, 0, icall_name);
+ return LLVMBuildCall (builder, callee, NULL, 0, "load_exception");
}
static LLVMValueRef
mono_llvm_emit_match_exception_call (EmitContext *ctx, LLVMBuilderRef builder, gint32 region_start, gint32 region_end)
{
- const char *icall_name = "mono_llvm_match_exception";
- const MonoJitICallId icall_id = MONO_JIT_ICALL_mono_llvm_match_exception;
+ const char *icall_name = "mini_llvmonly_match_exception";
+ const MonoJitICallId icall_id = MONO_JIT_ICALL_mini_llvmonly_match_exception;
ctx->builder = builder;
LLVMValueRef cast = LLVMBuildBitCast (lpadBuilder, ctx->module->sentinel_exception, LLVMPointerType (LLVMInt8Type (), 0), "int8TypeInfo");
LLVMAddClause (landing_pad, cast);
+ if (ctx->cfg->deopt) {
+ /*
+ * Call mini_llvmonly_resume_exception_il_state (lmf, il_state)
+ *
+ * The call will execute the catch clause and the rest of the method and store the return
+ * value into ctx->il_state_ret.
+ */
+ if (!ctx->has_catch) {
+ /* Unused */
+ LLVMBuildUnreachable (lpadBuilder);
+ return lpad_bb;
+ }
+
+ const MonoJitICallId icall_id = MONO_JIT_ICALL_mini_llvmonly_resume_exception_il_state;
+ LLVMValueRef callee;
+ LLVMValueRef args [2];
+
+ LLVMTypeRef fun_sig = LLVMFunctionType2 (LLVMVoidType (), IntPtrType (), IntPtrType (), FALSE);
+
+ callee = get_callee (ctx, fun_sig, MONO_PATCH_INFO_JIT_ICALL_ID, GUINT_TO_POINTER (icall_id));
+
+ g_assert (ctx->cfg->lmf_var);
+ g_assert (ctx->addresses [ctx->cfg->lmf_var->dreg]);
+ args [0] = LLVMBuildPtrToInt (ctx->builder, ctx->addresses [ctx->cfg->lmf_var->dreg], IntPtrType (), "");
+ args [1] = LLVMBuildPtrToInt (ctx->builder, ctx->il_state, IntPtrType (), "");
+ emit_call (ctx, NULL, &ctx->builder, callee, args, 2);
+
+ /* Return the value set in ctx->il_state_ret */
+
+ LLVMTypeRef ret_type = LLVMGetReturnType (LLVMGetElementType (LLVMTypeOf (ctx->lmethod)));
+ LLVMBuilderRef builder = ctx->builder;
+ LLVMValueRef addr, retval, gep, indexes [2];
+
+ switch (ctx->linfo->ret.storage) {
+ case LLVMArgNone:
+ LLVMBuildRetVoid (builder);
+ break;
+ case LLVMArgNormal:
+ case LLVMArgWasmVtypeAsScalar:
+ case LLVMArgVtypeInReg: {
+ if (ctx->sig->ret->type == MONO_TYPE_VOID) {
+ LLVMBuildRetVoid (builder);
+ break;
+ }
+
+ addr = ctx->il_state_ret;
+ g_assert (addr);
+
+ addr = convert (ctx, ctx->il_state_ret, LLVMPointerType (ret_type, 0));
+ indexes [0] = LLVMConstInt (LLVMInt32Type (), 0, FALSE);
+ indexes [1] = LLVMConstInt (LLVMInt32Type (), 0, FALSE);
+ gep = LLVMBuildGEP (builder, addr, indexes, 1, "");
+
+ LLVMBuildRet (builder, LLVMBuildLoad (builder, gep, ""));
+ break;
+ }
+ case LLVMArgVtypeRetAddr: {
+ LLVMValueRef ret_addr;
+
+ g_assert (cfg->vret_addr);
+ ret_addr = ctx->values [cfg->vret_addr->dreg];
+
+ addr = ctx->il_state_ret;
+ g_assert (addr);
+
+ /* The ret value is in il_state_ret, copy it to the memory pointed to by the vret arg */
+ ret_type = type_to_llvm_type (ctx, ctx->sig->ret);
+ indexes [0] = LLVMConstInt (LLVMInt32Type (), 0, FALSE);
+ indexes [1] = LLVMConstInt (LLVMInt32Type (), 0, FALSE);
+ gep = LLVMBuildGEP (builder, addr, indexes, 1, "");
+ retval = convert (ctx, LLVMBuildLoad (builder, gep, ""), ret_type);
+
+ LLVMBuildStore (builder, retval, convert (ctx, ret_addr, LLVMPointerType (ret_type, 0)));
+ LLVMBuildRetVoid (builder);
+ break;
+ }
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+
+ return lpad_bb;
+ }
+
LLVMBasicBlockRef resume_bb = gen_bb (ctx, "RESUME_BB");
LLVMBuilderRef resume_builder = create_builder (ctx);
ctx->builder = resume_builder;
}
#ifdef TARGET_WASM
- if (ctx->cfg->lmf_var) {
+ if (ctx->cfg->lmf_var && !ctx->cfg->deopt) {
LLVMValueRef callee;
LLVMValueRef args [1];
LLVMTypeRef sig = LLVMFunctionType1 (LLVMVoidType (), ctx->module->ptr_type, FALSE);
has_terminator = TRUE;
break;
}
+ case OP_ENDFILTER: {
+ g_assert (cfg->llvm_only && cfg->deopt);
+ LLVMBuildUnreachable (builder);
+ has_terminator = TRUE;
+ break;
+ }
case OP_IL_SEQ_POINT:
break;
default: {
clause = &header->clauses [i];
if (clause->flags != MONO_EXCEPTION_CLAUSE_FINALLY && clause->flags != MONO_EXCEPTION_CLAUSE_FAULT && clause->flags != MONO_EXCEPTION_CLAUSE_NONE) {
if (cfg->llvm_only) {
- if (!cfg->interp_entry_only)
+ if (!cfg->deopt && !cfg->interp_entry_only)
llvmonly_fail = TRUE;
} else {
set_failure (ctx, "non-finally/catch/fault clause.");
/* We can't handle inlined methods with clauses */
mono_llvm_add_func_attr (method, LLVM_ATTR_NO_INLINE);
+ for (int i = 0; i < cfg->header->num_clauses; i++) {
+ MonoExceptionClause *clause = &cfg->header->clauses [i];
+ if (clause->flags == MONO_EXCEPTION_CLAUSE_NONE || clause->flags == MONO_EXCEPTION_CLAUSE_FILTER)
+ ctx->has_catch = TRUE;
+ }
+
if (linfo->rgctx_arg) {
ctx->rgctx_arg = LLVMGetParam (method, linfo->rgctx_arg_pindex);
ctx->rgctx_arg_pindex = linfo->rgctx_arg_pindex;
if (ctx->cfg->interp_entry_only || !(bb->region != -1 && (bb->flags & BB_EXCEPTION_HANDLER)))
continue;
+ if (ctx->cfg->deopt && MONO_REGION_FLAGS (bb->region) == MONO_EXCEPTION_CLAUSE_FILTER)
+ continue;
+
clause_index = MONO_REGION_CLAUSE_INDEX (bb->region);
g_hash_table_insert (ctx->region_to_handler, GUINT_TO_POINTER (mono_get_block_region_notry (cfg, bb->region)), bb);
g_hash_table_insert (ctx->clause_to_handler, GINT_TO_POINTER (clause_index), bb);
g_assert (mono_get_lmf_addr == mono_tls_get_lmf_addr);
register_icall (mono_domain_get, mono_icall_sig_ptr, TRUE);
- register_icall (mono_llvm_throw_exception, mono_icall_sig_void_object, TRUE);
- register_icall (mono_llvm_rethrow_exception, mono_icall_sig_void_object, TRUE);
- register_icall (mono_llvm_resume_exception, mono_icall_sig_void, TRUE);
- register_icall (mono_llvm_match_exception, mono_icall_sig_int_ptr_int_int_ptr_object, TRUE);
- register_icall (mono_llvm_clear_exception, NULL, TRUE);
- register_icall (mono_llvm_load_exception, mono_icall_sig_object, TRUE);
- register_icall (mono_llvm_throw_corlib_exception, mono_icall_sig_void_int, TRUE);
+ register_icall (mini_llvmonly_throw_exception, mono_icall_sig_void_object, TRUE);
+ register_icall (mini_llvmonly_rethrow_exception, mono_icall_sig_void_object, TRUE);
+ register_icall (mini_llvmonly_throw_corlib_exception, mono_icall_sig_void_int, TRUE);
+ register_icall (mini_llvmonly_resume_exception, mono_icall_sig_void, TRUE);
+ register_icall (mini_llvmonly_resume_exception_il_state, mono_icall_sig_void_ptr_ptr, TRUE);
+ register_icall (mini_llvmonly_load_exception, mono_icall_sig_object, TRUE);
+ register_icall (mini_llvmonly_clear_exception, NULL, TRUE);
+ register_icall (mini_llvmonly_match_exception, mono_icall_sig_int_ptr_int_int_ptr_object, TRUE);
+
#if defined(ENABLE_LLVM) && defined(HAVE_UNWIND_H)
register_icall (mono_llvm_set_unhandled_exception_handler, NULL, TRUE);
gpointer ex_obj;
MonoLMF *lmf;
int first_filter_idx, filter_idx;
+ /* MonoMethodILState */
+ gpointer il_state;
} ResumeState;
typedef void (*MonoAbortFunction)(MonoObject*);
return MONO_RGCTX_ACCESS_THIS;
}
-static gboolean
-can_deopt (MonoCompile *cfg)
-{
- MonoMethodHeader *header = cfg->header;
-
- if (!header->num_clauses)
- return FALSE;
-
- /*
- * Currently, only finally/fault clauses are supported.
- * Catch clauses are hard to support, since even if the
- * rest of the method is executed by the interpreter, execution needs to
- * return to the caller which is an AOTed method.
- * Filter clauses could be supported, but every filter clause has an
- * associated catch clause.
- */
- 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)
- return FALSE;
- }
-
- return TRUE;
-}
-
/*
* mini_method_compile:
* @method: the method to compile
return cfg;
}
- if (cfg->llvm_only && cfg->interp && !cfg->interp_entry_only && header->num_clauses && can_deopt (cfg)) {
+ if (cfg->llvm_only && cfg->interp && !cfg->interp_entry_only && header->num_clauses) {
cfg->deopt = TRUE;
/* Can't reconstruct inlined state */
cfg->disable_inline = TRUE;
MONO_COMPONENT_API void mono_restore_context (MonoContext *ctx);
guint8* mono_jinfo_get_unwind_info (MonoJitInfo *ji, guint32 *unwind_info_len);
int mono_jinfo_get_epilog_size (MonoJitInfo *ji);
-G_EXTERN_C void mono_llvm_rethrow_exception (MonoObject *ex);
-G_EXTERN_C void mono_llvm_throw_exception (MonoObject *ex);
-G_EXTERN_C void mono_llvm_throw_corlib_exception (guint32 ex_token_index);
-G_EXTERN_C void mono_llvm_resume_exception (void);
-G_EXTERN_C void mono_llvm_clear_exception (void);
-G_EXTERN_C MonoObject *mono_llvm_load_exception (void);
-void mono_llvm_reset_exception (void);
-void mono_llvm_raise_exception (MonoException *e);
-void mono_llvm_reraise_exception (MonoException *e);
-G_EXTERN_C gint32 mono_llvm_match_exception (MonoJitInfo *jinfo, guint32 region_start, guint32 region_end, gpointer rgctx, MonoObject *this_obj);
gboolean
mono_find_jit_info_ext (MonoJitTlsData *jit_tls,
PROJECT_NAME=Wasm.Console.Bench.Sample.csproj
CONSOLE_DLL=Wasm.Console.Bench.Sample.dll
+MAIN_JS=test-main.js
run: run-console
<WasmMainJSPath>$(MonoProjectRoot)\wasm\test-main.js</WasmMainJSPath>
<WasmGenerateRunV8Script>true</WasmGenerateRunV8Script>
<SuppressTrimAnalysisWarnings>true</SuppressTrimAnalysisWarnings>
+ <WasmNativeStrip>false</WasmNativeStrip>
</PropertyGroup>
<PropertyGroup>