From: Andi McClure Date: Wed, 3 May 2017 17:45:44 +0000 (-0400) Subject: Merge pull request #4780 from xmcclure/assembly-loader-default X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=commitdiff_plain;h=00dff71419175c12ff2c294cf26092362e48d976;hp=ca6365b31664632788756053279590dee2daf183;p=mono.git Merge pull request #4780 from xmcclure/assembly-loader-default Document --assembly-loader and change default to 'legacy' --- diff --git a/mono/metadata/assembly.c b/mono/metadata/assembly.c index afcd5990b52..5bc9486f897 100644 --- a/mono/metadata/assembly.c +++ b/mono/metadata/assembly.c @@ -123,6 +123,9 @@ static const AssemblyVersionMap framework_assemblies [] = { {"Microsoft.Build.Utilities.v3.5", 2, "Microsoft.Build.Utilities.v4.0"}, {"Microsoft.VisualBasic", 1}, {"Microsoft.VisualC", 1}, + FACADE_ASSEMBLY ("Microsoft.Win32.Primitives"), + FACADE_ASSEMBLY ("Microsoft.Win32.Registry"), + FACADE_ASSEMBLY ("Microsoft.Win32.Registry.AccessControl"), {"Mono.Cairo", 0}, {"Mono.CompilerServices.SymbolWriter", 0}, {"Mono.Data", 0}, @@ -209,7 +212,6 @@ static const AssemblyVersionMap framework_assemblies [] = { {"System.Net.Http", 4}, {"System.Net.Http.Rtc", 0}, FACADE_ASSEMBLY ("System.Net.HttpListener"), - {"System.Net.NetworkInformation", 0}, FACADE_ASSEMBLY ("System.Net.Mail"), FACADE_ASSEMBLY ("System.Net.NameResolution"), FACADE_ASSEMBLY ("System.Net.NetworkInformation"), @@ -226,6 +228,7 @@ static const AssemblyVersionMap framework_assemblies [] = { {"System.Numerics.Vectors", 3}, FACADE_ASSEMBLY ("System.ObjectModel"), FACADE_ASSEMBLY ("System.Reflection"), + FACADE_ASSEMBLY ("System.Reflection.DispatchProxy"), FACADE_ASSEMBLY ("System.Reflection.Emit"), FACADE_ASSEMBLY ("System.Reflection.Emit.ILGeneration"), FACADE_ASSEMBLY ("System.Reflection.Emit.Lightweight"), @@ -245,7 +248,7 @@ static const AssemblyVersionMap framework_assemblies [] = { FACADE_ASSEMBLY ("System.Runtime.Numerics"), {"System.Runtime.Remoting", 0}, {"System.Runtime.Serialization", 3}, - {"System.Runtime.Serialization.Formatters", 3}, + FACADE_ASSEMBLY ("System.Runtime.Serialization.Formatters"), {"System.Runtime.Serialization.Formatters.Soap", 0}, FACADE_ASSEMBLY ("System.Runtime.Serialization.Json"), FACADE_ASSEMBLY ("System.Runtime.Serialization.Primitives"), @@ -275,11 +278,11 @@ static const AssemblyVersionMap framework_assemblies [] = { FACADE_ASSEMBLY ("System.Security.Principal.Windows"), FACADE_ASSEMBLY ("System.Security.SecureString"), {"System.ServiceModel", 3}, - {"System.ServiceModel.Duplex", 3}, - {"System.ServiceModel.Http", 3}, - {"System.ServiceModel.NetTcp", 3}, - {"System.ServiceModel.Primitives", 3}, - {"System.ServiceModel.Security", 3}, + FACADE_ASSEMBLY ("System.ServiceModel.Duplex"), + FACADE_ASSEMBLY ("System.ServiceModel.Http"), + FACADE_ASSEMBLY ("System.ServiceModel.NetTcp"), + FACADE_ASSEMBLY ("System.ServiceModel.Primitives"), + FACADE_ASSEMBLY ("System.ServiceModel.Security"), {"System.ServiceModel.Web", 2}, {"System.ServiceProcess", 0}, FACADE_ASSEMBLY ("System.ServiceProcess.ServiceController"), diff --git a/mono/metadata/debug-internals.h b/mono/metadata/debug-internals.h index 1d5e33cf250..5ac4f103adf 100644 --- a/mono/metadata/debug-internals.h +++ b/mono/metadata/debug-internals.h @@ -84,4 +84,7 @@ mono_debug_free_method_async_debug_info (MonoDebugMethodAsyncInfo *info); gboolean mono_debug_image_has_debug_info (MonoImage *image); +MonoDebugSourceLocation * +mono_debug_lookup_source_location_by_il (MonoMethod *method, guint32 il_offset, MonoDomain *domain); + #endif /* __DEBUG_INTERNALS_H__ */ diff --git a/mono/metadata/mono-debug.c b/mono/metadata/mono-debug.c index b1a40b6ae5f..4230399ec10 100644 --- a/mono/metadata/mono-debug.c +++ b/mono/metadata/mono-debug.c @@ -793,6 +793,40 @@ mono_debug_lookup_source_location (MonoMethod *method, guint32 address, MonoDoma return location; } +/** + * mono_debug_lookup_source_location_by_il: + * + * Same as mono_debug_lookup_source_location but take an IL_OFFSET argument. + */ +MonoDebugSourceLocation * +mono_debug_lookup_source_location_by_il (MonoMethod *method, guint32 il_offset, MonoDomain *domain) +{ + MonoDebugMethodInfo *minfo; + MonoDebugSourceLocation *location; + + if (mono_debug_format == MONO_DEBUG_FORMAT_NONE) + return NULL; + + mono_debugger_lock (); + minfo = mono_debug_lookup_method_internal (method); + if (!minfo || !minfo->handle) { + mono_debugger_unlock (); + return NULL; + } + + if (!minfo->handle->ppdb && (!minfo->handle->symfile || !mono_debug_symfile_is_loaded (minfo->handle->symfile))) { + mono_debugger_unlock (); + return NULL; + } + + if (minfo->handle->ppdb) + location = mono_ppdb_lookup_location (minfo, il_offset); + else + location = mono_debug_symfile_lookup_location (minfo, il_offset); + mono_debugger_unlock (); + return location; +} + MonoDebugSourceLocation * mono_debug_method_lookup_location (MonoDebugMethodInfo *minfo, int il_offset) { diff --git a/mono/metadata/object.c b/mono/metadata/object.c index c23c56bafb8..6c3466099d9 100644 --- a/mono/metadata/object.c +++ b/mono/metadata/object.c @@ -7826,7 +7826,7 @@ mono_delegate_ctor_with_method (MonoObject *this_obj, MonoObject *target, gpoint g_assert (method); method = mono_marshal_get_remoting_invoke (method); #ifdef ENABLE_INTERPRETER - g_error ("need RuntimeMethod in method_ptr when using interpreter"); + //g_error ("need RuntimeMethod in method_ptr when using interpreter"); #endif delegate->method_ptr = mono_compile_method_checked (method, error); return_val_if_nok (error, FALSE); diff --git a/mono/mini/exceptions-amd64.c b/mono/mini/exceptions-amd64.c index 846ad9744f5..e02cdb8b8b2 100644 --- a/mono/mini/exceptions-amd64.c +++ b/mono/mini/exceptions-amd64.c @@ -582,20 +582,24 @@ mono_arch_unwind_frame (MonoDomain *domain, MonoJitTlsData *jit_tls, guint64 rip; if (((guint64)(*lmf)->previous_lmf) & 2) { - /* - * This LMF entry is created by the soft debug code to mark transitions to - * managed code done during invokes. - */ MonoLMFExt *ext = (MonoLMFExt*)(*lmf); - g_assert (ext->debugger_invoke); - - memcpy (new_ctx, &ext->ctx, sizeof (MonoContext)); + if (ext->debugger_invoke) { + /* + * This LMF entry is created by the soft debug code to mark transitions to + * managed code done during invokes. + */ + frame->type = FRAME_TYPE_DEBUGGER_INVOKE; + memcpy (new_ctx, &ext->ctx, sizeof (MonoContext)); + } else if (ext->interp_exit) { + frame->type = FRAME_TYPE_INTERP_TO_MANAGED; + frame->interp_exit_data = ext->interp_exit_data; + } else { + g_assert_not_reached (); + } *lmf = (MonoLMF *)(((guint64)(*lmf)->previous_lmf) & ~7); - frame->type = FRAME_TYPE_DEBUGGER_INVOKE; - return TRUE; } diff --git a/mono/mini/interp/interp-internals.h b/mono/mini/interp/interp-internals.h index 9769855efac..69292518781 100644 --- a/mono/mini/interp/interp-internals.h +++ b/mono/mini/interp/interp-internals.h @@ -7,6 +7,7 @@ #include #include #include +#include #include "config.h" enum { @@ -88,6 +89,7 @@ typedef struct _RuntimeMethod gpointer jit_entry; MonoType *rtype; MonoType **param_types; + MonoJitInfo *jinfo; } RuntimeMethod; struct _MonoInvocation { @@ -115,6 +117,13 @@ typedef struct { jmp_buf *current_env; unsigned char search_for_handler; unsigned char managed_code; + + /* Resume state for resuming execution in mixed mode */ + gboolean has_resume_state; + /* Frame to resume execution at */ + MonoInvocation *handler_frame; + /* IP to resume execution at */ + gpointer handler_ip; } ThreadContext; extern int mono_interp_traceopt; diff --git a/mono/mini/interp/interp.c b/mono/mini/interp/interp.c index 0c0b651f563..1b74cc75f5e 100644 --- a/mono/mini/interp/interp.c +++ b/mono/mini/interp/interp.c @@ -107,7 +107,7 @@ void ves_exec_method (MonoInvocation *frame); static char* dump_stack (stackval *stack, stackval *sp); static char* dump_frame (MonoInvocation *inv); static MonoArray *get_trace_ips (MonoDomain *domain, MonoInvocation *top); -static void ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context, unsigned short *start_with_ip, MonoException *filter_exception); +static void ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context, unsigned short *start_with_ip, MonoException *filter_exception, int exit_at_finally); typedef void (*ICallMethod) (MonoInvocation *frame); @@ -148,7 +148,8 @@ db_match_method (gpointer data, gpointer user_data) break_on_method = 1; } -static void debug_enter (MonoInvocation *frame, int *tracing) +static void +debug_enter (MonoInvocation *frame, int *tracing) { if (db_methods) { g_list_foreach (db_methods, db_match_method, (gpointer)frame->runtime_method->method); @@ -198,6 +199,17 @@ static void debug_enter (MonoInvocation *frame, int *tracing) #endif +/* Set the current execution state to the resume state in context */ +#define SET_RESUME_STATE(context) do { \ + ip = (context)->handler_ip; \ + sp->data.p = frame->ex; \ + ++sp; \ + frame->ex = NULL; \ + (context)->has_resume_state = 0; \ + (context)->handler_frame = NULL; \ + goto main_loop; \ + } while (0) + static void interp_ex_handler (MonoException *ex) { MonoError error; @@ -902,6 +914,7 @@ ves_pinvoke_method (MonoInvocation *frame, MonoMethodSignature *sig, MonoFuncV a MonoInvocation *old_frame = context->current_frame; MonoInvocation *old_env_frame = context->env_frame; jmp_buf *old_env = context->current_env; + MonoLMFExt ext; if (setjmp (env)) { context->current_frame = old_frame; @@ -932,8 +945,20 @@ ves_pinvoke_method (MonoInvocation *frame, MonoMethodSignature *sig, MonoFuncV a context->current_frame = frame; context->managed_code = 0; + /* + * Push an LMF frame on the LMF stack + * to mark the transition to native code. + */ + memset (&ext, 0, sizeof (ext)); + ext.interp_exit = TRUE; + ext.interp_exit_data = frame; + + mono_push_lmf (&ext); + mono_interp_enter_icall_trampoline (addr, margs); + mono_pop_lmf (&ext.lmf); + context->managed_code = 1; /* domain can only be changed by native code */ context->domain = mono_domain_get (); @@ -1301,12 +1326,10 @@ mono_interp_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoOb if (context == NULL) { context = &context_struct; + memset (context, 0, sizeof (ThreadContext)); context_struct.base_frame = &frame; - context_struct.current_frame = NULL; context_struct.env_frame = &frame; context_struct.current_env = &env; - context_struct.search_for_handler = 0; - context_struct.managed_code = 0; mono_native_tls_set_value (thread_context_id, context); } else @@ -1427,7 +1450,7 @@ handle_enum: if (exc) frame.invoke_trap = 1; context->managed_code = 1; - ves_exec_method_with_context (&frame, context, NULL, NULL); + ves_exec_method_with_context (&frame, context, NULL, NULL, -1); context->managed_code = 0; if (context == &context_struct) mono_native_tls_set_value (thread_context_id, NULL); @@ -1567,7 +1590,7 @@ interp_entry (InterpEntryData *data) } } - init_frame (&frame, context->current_frame, data->rmethod, args, &result); + init_frame (&frame, NULL, data->rmethod, args, &result); context->managed_code = 1; type = rmethod->rtype; @@ -1583,7 +1606,7 @@ interp_entry (InterpEntryData *data) break; } - ves_exec_method_with_context (&frame, context, NULL, NULL); + ves_exec_method_with_context (&frame, context, NULL, NULL, -1); context->managed_code = 0; if (context == &context_struct) mono_native_tls_set_value (thread_context_id, NULL); @@ -2013,8 +2036,11 @@ static int opcode_counts[512]; #define MINT_IN_DEFAULT default: #endif +/* + * If EXIT_AT_FINALLY is not -1, exit after exiting the finally clause with that index. + */ static void -ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context, unsigned short *start_with_ip, MonoException *filter_exception) +ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context, unsigned short *start_with_ip, MonoException *filter_exception, int exit_at_finally) { MonoInvocation child_frame; GSList *finally_ips = NULL; @@ -2266,10 +2292,17 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context, uns } } - ves_exec_method_with_context (&child_frame, context, NULL, NULL); + ves_exec_method_with_context (&child_frame, context, NULL, NULL, -1); context->current_frame = frame; + if (context->has_resume_state) { + if (frame == context->handler_frame) + SET_RESUME_STATE (context); + else + goto exit_frame; + } + if (child_frame.ex) { /* * An exception occurred, need to run finally, fault and catch handlers.. @@ -2310,6 +2343,13 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context, uns context->current_frame = frame; + if (context->has_resume_state) { + if (frame == context->handler_frame) + SET_RESUME_STATE (context); + else + goto exit_frame; + } + if (child_frame.ex) { /* * An exception occurred, need to run finally, fault and catch handlers.. @@ -2350,10 +2390,17 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context, uns mono_error_cleanup (&error); /* FIXME: don't swallow the error */ } - ves_exec_method_with_context (&child_frame, context, NULL, NULL); + ves_exec_method_with_context (&child_frame, context, NULL, NULL, -1); context->current_frame = frame; + if (context->has_resume_state) { + if (frame == context->handler_frame) + SET_RESUME_STATE (context); + else + goto exit_frame; + } + if (child_frame.ex) { /* * An exception occurred, need to run finally, fault and catch handlers.. @@ -2390,10 +2437,17 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context, uns mono_error_cleanup (&error); /* FIXME: don't swallow the error */ } - ves_exec_method_with_context (&child_frame, context, NULL, NULL); + ves_exec_method_with_context (&child_frame, context, NULL, NULL, -1); context->current_frame = frame; + if (context->has_resume_state) { + if (frame == context->handler_frame) + SET_RESUME_STATE (context); + else + goto exit_frame; + } + if (child_frame.ex) { /* * An exception occurred, need to run finally, fault and catch handlers.. @@ -2410,6 +2464,7 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context, uns MonoFtnDesc ftndesc; guint8 res_buf [256]; MonoType *type; + MonoLMFExt ext; //printf ("%s\n", mono_method_full_name (rmethod->method, 1)); @@ -2506,6 +2561,16 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context, uns } } + /* + * Push an LMF frame on the LMF stack + * to mark the transition to compiled code. + */ + memset (&ext, 0, sizeof (ext)); + ext.interp_exit = TRUE; + ext.interp_exit_data = frame; + + mono_push_lmf (&ext); + switch (pindex) { case 0: { void (*func)(gpointer) = rmethod->jit_wrapper; @@ -2560,6 +2625,21 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context, uns break; } + mono_pop_lmf (&ext.lmf); + + if (context->has_resume_state) { + /* + * If this bit is set, it means the call has thrown the exception, and we + * reached this point because the EH code in mono_handle_exception () + * unwound all the JITted frames below us. mono_interp_set_resume_state () + * has set the fields in context to indicate where we have to resume execution. + */ + if (frame == context->handler_frame) + SET_RESUME_STATE (context); + else + goto exit_frame; + } + MonoType *rtype = rmethod->rtype; switch (rtype->type) { case MONO_TYPE_VOID: @@ -2640,10 +2720,17 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context, uns sp [0].data.p = unboxed; } - ves_exec_method_with_context (&child_frame, context, NULL, NULL); + ves_exec_method_with_context (&child_frame, context, NULL, NULL, -1); context->current_frame = frame; + if (context->has_resume_state) { + if (frame == context->handler_frame) + SET_RESUME_STATE (context); + else + goto exit_frame; + } + if (child_frame.ex) { /* * An exception occurred, need to run finally, fault and catch handlers.. @@ -2687,10 +2774,17 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context, uns sp [0].data.p = unboxed; } - ves_exec_method_with_context (&child_frame, context, NULL, NULL); + ves_exec_method_with_context (&child_frame, context, NULL, NULL, -1); context->current_frame = frame; + if (context->has_resume_state) { + if (frame == context->handler_frame) + SET_RESUME_STATE (context); + else + goto exit_frame; + } + if (child_frame.ex) { /* * An exception occurred, need to run finally, fault and catch handlers.. @@ -3477,10 +3571,17 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context, uns g_assert (csig->call_convention == MONO_CALL_DEFAULT); - ves_exec_method_with_context (&child_frame, context, NULL, NULL); + ves_exec_method_with_context (&child_frame, context, NULL, NULL, -1); context->current_frame = frame; + if (context->has_resume_state) { + if (frame == context->handler_frame) + SET_RESUME_STATE (context); + else + goto exit_frame; + } + if (child_frame.ex) { /* * An exception occurred, need to run finally, fault and catch handlers.. @@ -4266,6 +4367,10 @@ array_constructed: BINOP_CAST(l, -, guint64); MINT_IN_BREAK; MINT_IN_CASE(MINT_ENDFINALLY) + ip ++; + int clause_index = *ip; + if (clause_index == exit_at_finally) + goto exit_frame; while (sp > frame->stack) { --sp; } @@ -4739,7 +4844,7 @@ array_constructed: stackval retval; memcpy (&dup_frame, inv, sizeof (MonoInvocation)); dup_frame.retval = &retval; - ves_exec_method_with_context (&dup_frame, context, inv->runtime_method->code + clause->data.filter_offset, frame->ex); + ves_exec_method_with_context (&dup_frame, context, inv->runtime_method->code + clause->data.filter_offset, frame->ex, -1); if (dup_frame.retval->data.i) { #if DEBUG_INTERP if (tracing) @@ -4917,7 +5022,7 @@ ves_exec_method (MonoInvocation *frame) frame->runtime_method = mono_interp_get_runtime_method (context->domain, frame->method, &error); mono_error_cleanup (&error); /* FIXME: don't swallow the error */ context->managed_code = 1; - ves_exec_method_with_context (frame, context, NULL, NULL); + ves_exec_method_with_context (frame, context, NULL, NULL, -1); context->managed_code = 0; if (frame->ex) { if (context != &context_struct && context->current_env) { @@ -5264,3 +5369,77 @@ mono_interp_regression_list (int verbose, int count, char *images []) return total; } +/* + * mono_interp_set_resume_state: + * + * Set the state the interpeter will continue to execute from after execution returns to the interpreter. + */ +void +mono_interp_set_resume_state (MonoException *ex, StackFrameInfo *frame, gpointer handler_ip) +{ + ThreadContext *context = mono_native_tls_get_value (thread_context_id); + + context->has_resume_state = TRUE; + context->handler_frame = frame->interp_frame; + /* This is on the stack, so it doesn't need a wbarrier */ + context->handler_frame->ex = ex; + context->handler_ip = handler_ip; +} + +/* + * mono_interp_run_finally: + * + * Run the finally clause identified by CLAUSE_INDEX in the intepreter frame given by + * frame->interp_frame. + */ +void +mono_interp_run_finally (StackFrameInfo *frame, int clause_index, gpointer handler_ip) +{ + MonoInvocation *iframe = frame->interp_frame; + ThreadContext *context = mono_native_tls_get_value (thread_context_id); + + ves_exec_method_with_context (iframe, context, handler_ip, NULL, clause_index); +} + +typedef struct { + MonoInvocation *current; +} StackIter; + +/* + * mono_interp_frame_iter_init: + * + * Initialize an iterator for iterating through interpreted frames. + */ +void +mono_interp_frame_iter_init (MonoInterpStackIter *iter, gpointer interp_exit_data) +{ + StackIter *stack_iter = (StackIter*)iter; + + stack_iter->current = (MonoInvocation*)interp_exit_data; +} + +gboolean +mono_interp_frame_iter_next (MonoInterpStackIter *iter, StackFrameInfo *frame) +{ + StackIter *stack_iter = (StackIter*)iter; + MonoInvocation *iframe = stack_iter->current; + + memset (frame, 0, sizeof (StackFrameInfo)); + /* pinvoke frames doesn't have runtime_method set */ + while (iframe && !iframe->runtime_method) + iframe = iframe->parent; + if (!iframe) + return FALSE; + + frame->type = FRAME_TYPE_INTERP; + frame->interp_frame = iframe; + frame->method = iframe->runtime_method->method; + frame->actual_method = frame->method; + /* This is the offset in the interpreter IR */ + frame->native_offset = iframe->ip - iframe->runtime_method->code; + frame->ji = iframe->runtime_method->jinfo; + + stack_iter->current = iframe->parent; + + return TRUE; +} diff --git a/mono/mini/interp/interp.h b/mono/mini/interp/interp.h index 951c47c85e1..8d83bf40149 100644 --- a/mono/mini/interp/interp.h +++ b/mono/mini/interp/interp.h @@ -6,6 +6,13 @@ #define __MONO_MINI_INTERPRETER_H__ #include +typedef struct _MonoInterpStackIter MonoInterpStackIter; + +/* Needed for stack allocation */ +struct _MonoInterpStackIter { + gpointer dummy [8]; +}; + int mono_interp_regression_list (int verbose, int count, char *images []); @@ -29,4 +36,17 @@ mono_interp_parse_options (const char *options); void interp_walk_stack_with_ctx (MonoInternalStackWalk func, MonoContext *ctx, MonoUnwindOptions options, void *user_data); + +void +mono_interp_set_resume_state (MonoException *ex, StackFrameInfo *frame, gpointer handler_ip); + +void +mono_interp_run_finally (StackFrameInfo *frame, int clause_index, gpointer handler_ip); + +void +mono_interp_frame_iter_init (MonoInterpStackIter *iter, gpointer interp_exit_data); + +gboolean +mono_interp_frame_iter_next (MonoInterpStackIter *iter, StackFrameInfo *frame); + #endif /* __MONO_MINI_INTERPRETER_H__ */ diff --git a/mono/mini/interp/mintops.def b/mono/mini/interp/mintops.def index 6e3e4dbd9e1..68a559f6db5 100644 --- a/mono/mini/interp/mintops.def +++ b/mono/mini/interp/mintops.def @@ -172,7 +172,7 @@ OPDEF(MINT_LEAVE_S, "leave.s", 2, MintOpShortBranch) OPDEF(MINT_THROW, "throw", 1, MintOpNoArgs) OPDEF(MINT_RETHROW, "rethrow", 1, MintOpNoArgs) -OPDEF(MINT_ENDFINALLY, "endfinally", 1, MintOpNoArgs) +OPDEF(MINT_ENDFINALLY, "endfinally", 2, MintOpNoArgs) OPDEF(MINT_BRFALSE_I4, "brfalse.i4", 3, MintOpBranch) OPDEF(MINT_BRFALSE_I8, "brfalse.i8", 3, MintOpBranch) diff --git a/mono/mini/interp/transform.c b/mono/mini/interp/transform.c index d76c9af55a7..182ef3ac84f 100644 --- a/mono/mini/interp/transform.c +++ b/mono/mini/interp/transform.c @@ -64,6 +64,7 @@ typedef struct int max_data_items; void **data_items; GHashTable *data_hash; + int *clause_indexes; } TransformData; #define MINT_TYPE_I1 0 @@ -932,6 +933,35 @@ interp_field_from_token (MonoMethod *method, guint32 token, MonoClass **klass, M return field; } +static void +interp_save_debug_info (RuntimeMethod *rtm, MonoMethodHeader *header, TransformData *td, GArray *line_numbers) +{ + MonoDebugMethodJitInfo *dinfo; + int i; + + if (!mono_debug_enabled ()) + return; + + /* + * We save the debug info in the same way the JIT does it, treating the interpreter IR as the native code. + */ + + dinfo = g_new0 (MonoDebugMethodJitInfo, 1); + dinfo->num_locals = header->num_locals; + dinfo->locals = g_new0 (MonoDebugVarInfo, header->num_locals); + dinfo->code_start = (guint8*)rtm->code; + dinfo->code_size = td->new_ip - td->new_code; + dinfo->epilogue_begin = 0; + dinfo->has_var_info = FALSE; + dinfo->num_line_numbers = line_numbers->len; + dinfo->line_numbers = g_new0 (MonoDebugLineNumberEntry, dinfo->num_line_numbers); + for (i = 0; i < dinfo->num_line_numbers; i++) + dinfo->line_numbers [i] = g_array_index (line_numbers, MonoDebugLineNumberEntry, i); + mono_debug_add_method (rtm->method, dinfo, mono_domain_get ()); + + mono_debug_free_method_jit_info (dinfo); +} + static void generate (MonoMethod *method, RuntimeMethod *rtm, unsigned char *is_bb_start, MonoGenericContext *generic_context) { @@ -952,6 +982,7 @@ generate (MonoMethod *method, RuntimeMethod *rtm, unsigned char *is_bb_start, Mo guint32 token; TransformData td; int generating_code = 1; + GArray *line_numbers; memset(&td, 0, sizeof(td)); td.method = method; @@ -972,10 +1003,12 @@ generate (MonoMethod *method, RuntimeMethod *rtm, unsigned char *is_bb_start, Mo td.max_data_items = 0; td.data_items = NULL; td.data_hash = g_hash_table_new (NULL, NULL); + td.clause_indexes = g_malloc (header->code_size * sizeof (int)); rtm->data_items = td.data_items; for (i = 0; i < header->code_size; i++) { td.forward_refs [i] = -1; td.stack_height [i] = -1; + td.clause_indexes [i] = -1; } td.new_ip = td.new_code; td.last_new_ip = NULL; @@ -984,6 +1017,8 @@ generate (MonoMethod *method, RuntimeMethod *rtm, unsigned char *is_bb_start, Mo td.sp = td.stack; td.max_stack_height = 0; + line_numbers = g_array_new (FALSE, TRUE, sizeof (MonoDebugLineNumberEntry)); + for (i = 0; i < header->num_clauses; i++) { MonoExceptionClause *c = header->clauses + i; td.stack_height [c->handler_offset] = 0; @@ -1005,6 +1040,13 @@ generate (MonoMethod *method, RuntimeMethod *rtm, unsigned char *is_bb_start, Mo td.stack_state [c->data.filter_offset][0].type = STACK_TYPE_O; td.stack_state [c->data.filter_offset][0].klass = NULL; /*FIX*/ } + + if ((c->flags & MONO_EXCEPTION_CLAUSE_FINALLY) || (c->flags & MONO_EXCEPTION_CLAUSE_FAULT)) { + for (int j = c->handler_offset; j < c->handler_offset + c->handler_len; ++j) { + if (td.clause_indexes [j] == -1) + td.clause_indexes [j] = i; + } + } } td.ip = header->code; @@ -1043,6 +1085,12 @@ generate (MonoMethod *method, RuntimeMethod *rtm, unsigned char *is_bb_start, Mo td.in_offsets [in_offset] = td.new_ip - td.new_code; new_in_start_offset = td.new_ip - td.new_code; td.in_start = td.ip; + + MonoDebugLineNumberEntry lne; + lne.native_offset = td.new_ip - td.new_code; + lne.il_offset = td.ip - header->code; + g_array_append_val (line_numbers, lne); + while (td.forward_refs [in_offset] >= 0) { int j = td.forward_refs [in_offset]; int slot; @@ -2823,8 +2871,10 @@ generate (MonoMethod *method, RuntimeMethod *rtm, unsigned char *is_bb_start, Mo ++td.ip; break; case CEE_ENDFINALLY: + g_assert (td.clause_indexes [in_offset] != -1); td.sp = td.stack; SIMPLE_OP (td, MINT_ENDFINALLY); + ADD_CODE (&td, td.clause_indexes [in_offset]); generating_code = 0; break; case CEE_LEAVE: @@ -3278,6 +3328,8 @@ generate (MonoMethod *method, RuntimeMethod *rtm, unsigned char *is_bb_start, Mo } g_assert (td.max_stack_height <= (header->max_stack + 1)); + int code_len = td.new_ip - td.new_code; + rtm->clauses = mono_domain_alloc0 (domain, header->num_clauses * sizeof (MonoExceptionClause)); memcpy (rtm->clauses, header->clauses, header->num_clauses * sizeof(MonoExceptionClause)); rtm->code = mono_domain_alloc0 (domain, (td.new_ip - td.new_code) * sizeof (gushort)); @@ -3300,6 +3352,29 @@ generate (MonoMethod *method, RuntimeMethod *rtm, unsigned char *is_bb_start, Mo rtm->alloca_size = rtm->locals_size + rtm->args_size + rtm->vt_stack_size + rtm->stack_size; rtm->data_items = mono_domain_alloc0 (domain, td.n_data_items * sizeof (td.data_items [0])); memcpy (rtm->data_items, td.data_items, td.n_data_items * sizeof (td.data_items [0])); + + /* Save debug info */ + interp_save_debug_info (rtm, header, &td, line_numbers); + + /* Create a MonoJitInfo for the interpreted method by creating the interpreter IR as the native code. */ + int jinfo_len = mono_jit_info_size (0, header->num_clauses, 0); + MonoJitInfo *jinfo = (MonoJitInfo *)mono_domain_alloc0 (domain, jinfo_len); + rtm->jinfo = jinfo; + mono_jit_info_init (jinfo, method, (guint8*)rtm->code, code_len, 0, header->num_clauses, 0); + for (i = 0; i < jinfo->num_clauses; ++i) { + MonoJitExceptionInfo *ei = &jinfo->clauses [i]; + MonoExceptionClause *c = rtm->clauses + i; + + ei->flags = c->flags; + ei->try_start = rtm->code + c->try_offset; + ei->try_end = rtm->code + c->try_offset + c->try_len; + ei->handler_start = rtm->code + c->handler_offset; + if (ei->flags == MONO_EXCEPTION_CLAUSE_FILTER || ei->flags == MONO_EXCEPTION_CLAUSE_FINALLY) { + } else { + ei->data.catch_class = c->data.catch_class; + } + } + g_free (td.in_offsets); g_free (td.forward_refs); for (i = 0; i < header->code_size; ++i) @@ -3310,6 +3385,8 @@ generate (MonoMethod *method, RuntimeMethod *rtm, unsigned char *is_bb_start, Mo g_free (td.data_items); g_free (td.stack); g_hash_table_destroy (td.data_hash); + g_free (td.clause_indexes); + g_array_free (line_numbers, TRUE); } static mono_mutex_t calc_section; diff --git a/mono/mini/mini-amd64.h b/mono/mini/mini-amd64.h index d13bca95ee1..b42ac52a33b 100644 --- a/mono/mini/mini-amd64.h +++ b/mono/mini/mini-amd64.h @@ -447,6 +447,7 @@ typedef struct { #define MONO_ARCH_HAVE_PATCH_CODE_NEW 1 #define MONO_ARCH_HAVE_OP_GENERIC_CLASS_INIT 1 #define MONO_ARCH_HAVE_GENERAL_RGCTX_LAZY_FETCH_TRAMPOLINE 1 +#define MONO_ARCH_HAVE_INIT_LMF_EXT 1 #if defined(TARGET_OSX) || defined(__linux__) #define MONO_ARCH_HAVE_UNWIND_BACKTRACE 1 diff --git a/mono/mini/mini-exceptions.c b/mono/mini/mini-exceptions.c index 45ceb0d6629..90d85b88ab4 100644 --- a/mono/mini/mini-exceptions.c +++ b/mono/mini/mini-exceptions.c @@ -58,6 +58,7 @@ #include #include #include +#include #include #include #include @@ -567,7 +568,7 @@ mono_find_jit_info_ext (MonoDomain *domain, MonoJitTlsData *jit_tls, if (!err) return FALSE; - if (*lmf && ((*lmf) != jit_tls->first_lmf) && ((gpointer)MONO_CONTEXT_GET_SP (new_ctx) >= (gpointer)(*lmf))) { + if (frame->type != FRAME_TYPE_INTERP_TO_MANAGED && *lmf && ((*lmf) != jit_tls->first_lmf) && ((gpointer)MONO_CONTEXT_GET_SP (new_ctx) >= (gpointer)(*lmf))) { /* * Remove any unused lmf. * Mask out the lower bits which might be used to hold additional information. @@ -630,6 +631,44 @@ mono_find_jit_info_ext (MonoDomain *domain, MonoJitTlsData *jit_tls, return TRUE; } +typedef struct { + gboolean in_interp; + MonoInterpStackIter interp_iter; +} Unwinder; + +static void +unwinder_init (Unwinder *unwinder) +{ + memset (unwinder, 0, sizeof (Unwinder)); +} + +static gboolean +unwinder_unwind_frame (Unwinder *unwinder, + MonoDomain *domain, MonoJitTlsData *jit_tls, + MonoJitInfo *prev_ji, MonoContext *ctx, + MonoContext *new_ctx, char **trace, MonoLMF **lmf, + mgreg_t **save_locations, + StackFrameInfo *frame) +{ + if (unwinder->in_interp) { + unwinder->in_interp = mono_interp_frame_iter_next (&unwinder->interp_iter, frame); + if (!unwinder->in_interp) { + return unwinder_unwind_frame (unwinder, domain, jit_tls, prev_ji, ctx, new_ctx, trace, lmf, save_locations, frame); + } + return TRUE; + } else { + gboolean res = mono_find_jit_info_ext (domain, jit_tls, prev_ji, ctx, new_ctx, trace, lmf, + save_locations, frame); + if (!res) + return FALSE; + if (frame->type == FRAME_TYPE_INTERP_TO_MANAGED) { + unwinder->in_interp = TRUE; + mono_interp_frame_iter_init (&unwinder->interp_iter, frame->interp_exit_data); + } + return TRUE; + } +} + /* * This function is async-safe. */ @@ -1119,6 +1158,8 @@ ves_icall_get_frame_info (gint32 skip, MonoBoolean need_file_info, MonoMethod *jmethod = NULL, *actual_method; StackFrameInfo frame; gboolean res; + Unwinder unwinder; + int il_offset = -1; MONO_ARCH_CONTEXT_DEF; @@ -1160,29 +1201,43 @@ ves_icall_get_frame_info (gint32 skip, MonoBoolean need_file_info, MONO_INIT_CONTEXT_FROM_FUNC (&ctx, ves_icall_get_frame_info); #endif + unwinder_init (&unwinder); + new_ctx = ctx; do { ctx = new_ctx; - res = mono_find_jit_info_ext (domain, jit_tls, NULL, &ctx, &new_ctx, NULL, &lmf, NULL, &frame); + res = unwinder_unwind_frame (&unwinder, domain, jit_tls, NULL, &ctx, &new_ctx, NULL, &lmf, NULL, &frame); if (!res) return FALSE; - - if (frame.type == FRAME_TYPE_MANAGED_TO_NATIVE || - frame.type == FRAME_TYPE_DEBUGGER_INVOKE || - frame.type == FRAME_TYPE_TRAMPOLINE) + switch (frame.type) { + case FRAME_TYPE_MANAGED_TO_NATIVE: + case FRAME_TYPE_DEBUGGER_INVOKE: + case FRAME_TYPE_TRAMPOLINE: + case FRAME_TYPE_INTERP_TO_MANAGED: continue; + case FRAME_TYPE_INTERP: + skip--; + break; + default: + ji = frame.ji; + *native_offset = frame.native_offset; - ji = frame.ji; - *native_offset = frame.native_offset; - - /* The skip count passed by the caller depends on us not filtering out MANAGED_TO_NATIVE */ - jmethod = jinfo_get_method (ji); - if (jmethod->wrapper_type != MONO_WRAPPER_NONE && jmethod->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD && jmethod->wrapper_type != MONO_WRAPPER_MANAGED_TO_NATIVE) - continue; - skip--; + /* The skip count passed by the caller depends on us not filtering out MANAGED_TO_NATIVE */ + jmethod = jinfo_get_method (ji); + if (jmethod->wrapper_type != MONO_WRAPPER_NONE && jmethod->wrapper_type != MONO_WRAPPER_DYNAMIC_METHOD && jmethod->wrapper_type != MONO_WRAPPER_MANAGED_TO_NATIVE) + continue; + skip--; + break; + } } while (skip >= 0); - actual_method = get_method_from_stack_frame (ji, get_generic_info_from_stack_frame (ji, &ctx)); + if (frame.type == FRAME_TYPE_INTERP) { + jmethod = frame.method; + actual_method = frame.actual_method; + *native_offset = frame.native_offset; + } else { + actual_method = get_method_from_stack_frame (ji, get_generic_info_from_stack_frame (ji, &ctx)); + } } MonoReflectionMethod *rm = mono_method_get_object_checked (domain, actual_method, NULL, &error); @@ -1192,7 +1247,11 @@ ves_icall_get_frame_info (gint32 skip, MonoBoolean need_file_info, } mono_gc_wbarrier_generic_store (method, (MonoObject*) rm); - location = mono_debug_lookup_source_location (jmethod, *native_offset, domain); + if (il_offset != -1) { + location = mono_debug_lookup_source_location_by_il (jmethod, il_offset, domain); + } else { + location = mono_debug_lookup_source_location (jmethod, *native_offset, domain); + } if (location) *iloffset = location->il_offset; else @@ -1469,6 +1528,8 @@ mono_handle_exception_internal_first_pass (MonoContext *ctx, MonoObject *obj, gi gint32 filter_idx; int i; MonoObject *ex_obj; + Unwinder unwinder; + gboolean in_interp; g_assert (ctx != NULL); @@ -1508,6 +1569,8 @@ mono_handle_exception_internal_first_pass (MonoContext *ctx, MonoObject *obj, gi filter_idx = 0; initial_ctx = *ctx; + unwinder_init (&unwinder); + while (1) { MonoContext new_ctx; guint32 free_stack; @@ -1519,24 +1582,37 @@ mono_handle_exception_internal_first_pass (MonoContext *ctx, MonoObject *obj, gi if (out_prev_ji) *out_prev_ji = ji; - unwind_res = mono_find_jit_info_ext (domain, jit_tls, NULL, ctx, &new_ctx, NULL, &lmf, NULL, &frame); - if (unwind_res) { - if (frame.type == FRAME_TYPE_DEBUGGER_INVOKE || - frame.type == FRAME_TYPE_MANAGED_TO_NATIVE || - frame.type == FRAME_TYPE_TRAMPOLINE) { - *ctx = new_ctx; - continue; - } - g_assert (frame.type == FRAME_TYPE_MANAGED); - ji = frame.ji; - } - + unwind_res = unwinder_unwind_frame (&unwinder, domain, jit_tls, NULL, ctx, &new_ctx, NULL, &lmf, NULL, &frame); if (!unwind_res) { setup_stack_trace (mono_ex, dynamic_methods, &trace_ips); g_slist_free (dynamic_methods); return FALSE; } + switch (frame.type) { + case FRAME_TYPE_DEBUGGER_INVOKE: + case FRAME_TYPE_MANAGED_TO_NATIVE: + case FRAME_TYPE_TRAMPOLINE: + case FRAME_TYPE_INTERP_TO_MANAGED: + *ctx = new_ctx; + continue; + case FRAME_TYPE_INTERP: + case FRAME_TYPE_MANAGED: + break; + default: + g_assert_not_reached (); + break; + } + + in_interp = frame.type == FRAME_TYPE_INTERP; + ji = frame.ji; + + gpointer ip; + if (in_interp) + ip = (guint16*)ji->code_start + frame.native_offset; + else + ip = MONO_CONTEXT_GET_IP (ctx); + frame_count ++; method = jinfo_get_method (ji); //printf ("M: %s %d.\n", mono_method_full_name (method, TRUE), frame_count); @@ -1578,7 +1654,7 @@ mono_handle_exception_internal_first_pass (MonoContext *ctx, MonoObject *obj, gi if (free_stack <= (64 * 1024)) continue; - if (is_address_protected (ji, ei, MONO_CONTEXT_GET_IP (ctx))) { + if (is_address_protected (ji, ei, ip)) { /* catch block */ MonoClass *catch_class = get_exception_catch_class (ei, ji, ctx); @@ -1650,7 +1726,8 @@ mono_handle_exception_internal_first_pass (MonoContext *ctx, MonoObject *obj, gi *out_ji = ji; /* mono_debugger_agent_handle_exception () needs this */ - MONO_CONTEXT_SET_IP (ctx, ei->handler_start); + if (!in_interp) + MONO_CONTEXT_SET_IP (ctx, ei->handler_start); return TRUE; } mono_error_cleanup (&isinst_error); @@ -1687,6 +1764,8 @@ mono_handle_exception_internal (MonoContext *ctx, MonoObject *obj, gboolean resu int i; MonoObject *ex_obj; MonoObject *non_exception = NULL; + Unwinder unwinder; + gboolean in_interp; g_assert (ctx != NULL); if (!obj) { @@ -1849,11 +1928,15 @@ mono_handle_exception_internal (MonoContext *ctx, MonoObject *obj, gboolean resu filter_idx = 0; initial_ctx = *ctx; + unwinder_init (&unwinder); + while (1) { MonoContext new_ctx; guint32 free_stack; int clause_index_start = 0; gboolean unwind_res = TRUE; + StackFrameInfo frame; + gpointer ip; if (resume) { resume = FALSE; @@ -1864,27 +1947,36 @@ mono_handle_exception_internal (MonoContext *ctx, MonoObject *obj, gboolean resu first_filter_idx = jit_tls->resume_state.first_filter_idx; filter_idx = jit_tls->resume_state.filter_idx; } else { - StackFrameInfo frame; - - unwind_res = mono_find_jit_info_ext (domain, jit_tls, NULL, ctx, &new_ctx, NULL, &lmf, NULL, &frame); - if (unwind_res) { - if (frame.type == FRAME_TYPE_DEBUGGER_INVOKE || - frame.type == FRAME_TYPE_MANAGED_TO_NATIVE || - frame.type == FRAME_TYPE_TRAMPOLINE) { - *ctx = new_ctx; - continue; - } - g_assert (frame.type == FRAME_TYPE_MANAGED); - ji = frame.ji; + unwind_res = unwinder_unwind_frame (&unwinder, domain, jit_tls, NULL, ctx, &new_ctx, NULL, &lmf, NULL, &frame); + if (!unwind_res) { + *(mono_get_lmf_addr ()) = lmf; + + jit_tls->abort_func (obj); + g_assert_not_reached (); + } + switch (frame.type) { + case FRAME_TYPE_DEBUGGER_INVOKE: + case FRAME_TYPE_MANAGED_TO_NATIVE: + case FRAME_TYPE_TRAMPOLINE: + *ctx = new_ctx; + continue; + case FRAME_TYPE_INTERP_TO_MANAGED: + continue; + case FRAME_TYPE_INTERP: + case FRAME_TYPE_MANAGED: + break; + default: + g_assert_not_reached (); + break; } + in_interp = frame.type == FRAME_TYPE_INTERP; + ji = frame.ji; } - if (!unwind_res) { - *(mono_get_lmf_addr ()) = lmf; - - jit_tls->abort_func (obj); - g_assert_not_reached (); - } + if (in_interp) + ip = (guint16*)ji->code_start + frame.native_offset; + else + ip = MONO_CONTEXT_GET_IP (ctx); method = jinfo_get_method (ji); frame_count ++; @@ -1910,7 +2002,7 @@ mono_handle_exception_internal (MonoContext *ctx, MonoObject *obj, gboolean resu if (free_stack <= (64 * 1024)) continue; - if (is_address_protected (ji, ei, MONO_CONTEXT_GET_IP (ctx))) { + if (is_address_protected (ji, ei, ip)) { /* catch block */ MonoClass *catch_class = get_exception_catch_class (ei, ji, ctx); @@ -1993,7 +2085,27 @@ mono_handle_exception_internal (MonoContext *ctx, MonoObject *obj, gboolean resu mono_profiler_exception_clause_handler (method, ei->flags, i); jit_tls->orig_ex_ctx_set = FALSE; mini_set_abort_threshold (ctx); - MONO_CONTEXT_SET_IP (ctx, ei->handler_start); + + if (in_interp) { + /* + * ctx->pc points into the interpreter, after the call which transitioned to + * JITted code. Store the unwind state into the + * interpeter state, then resume, the interpreter will unwind itself until + * it reaches the target frame and will continue execution from there. + * The resuming is kinda hackish, from the native code standpoint, it looks + * like the call which transitioned to JITted code has succeeded, but the + * return value register etc. is not set, so we have to be careful. + */ + mono_interp_set_resume_state (mono_ex, &frame, ei->handler_start); + /* Undo the IP adjustment done by mono_arch_unwind_frame () */ +#ifdef TARGET_AMD64 + ctx->gregs [AMD64_RIP] ++; +#else + NOT_IMPLEMENTED; +#endif + } else { + MONO_CONTEXT_SET_IP (ctx, ei->handler_start); + } mono_set_lmf (lmf); #ifndef DISABLE_PERFCOUNTERS mono_perfcounters->exceptions_depth += frame_count; @@ -2045,7 +2157,10 @@ mono_handle_exception_internal (MonoContext *ctx, MonoObject *obj, gboolean resu return 0; } else { mini_set_abort_threshold (ctx); - call_filter (ctx, ei->handler_start); + if (in_interp) + mono_interp_run_finally (&frame, i, ei->handler_start); + else + call_filter (ctx, ei->handler_start); } } } @@ -3251,3 +3366,31 @@ mono_debug_personality (void) g_assert_not_reached (); } #endif + +#ifndef ENABLE_INTERPRETER +/* Stubs of interpreter functions */ +void +mono_interp_set_resume_state (MonoException *ex, StackFrameInfo *frame, gpointer handler_ip) +{ + g_assert_not_reached (); +} + +void +mono_interp_run_finally (StackFrameInfo *frame, int clause_index, gpointer handler_ip) +{ + g_assert_not_reached (); +} + +void +mono_interp_frame_iter_init (MonoInterpStackIter *iter, gpointer interp_exit_data) +{ + g_assert_not_reached (); +} + +gboolean +mono_interp_frame_iter_next (MonoInterpStackIter *iter, StackFrameInfo *frame) +{ + g_assert_not_reached (); + return FALSE; +} +#endif diff --git a/mono/mini/mini-generic-sharing.c b/mono/mini/mini-generic-sharing.c index 587d368a418..d7475aebd3a 100644 --- a/mono/mini/mini-generic-sharing.c +++ b/mono/mini/mini-generic-sharing.c @@ -1493,7 +1493,8 @@ mini_get_interp_in_wrapper (MonoMethodSignature *sig) mb = mono_mb_new (mono_defaults.object_class, name, MONO_WRAPPER_UNKNOWN); - // FIXME: save lmf + /* This is needed to be able to unwind out of interpreted code */ + mb->method->save_lmf = 1; #ifndef DISABLE_JIT if (sig->ret->type != MONO_TYPE_VOID) diff --git a/mono/mini/mini-runtime.c b/mono/mini/mini-runtime.c index 719dceaf97e..5085233d27a 100644 --- a/mono/mini/mini-runtime.c +++ b/mono/mini/mini-runtime.c @@ -791,6 +791,38 @@ mono_set_lmf_addr (gpointer lmf_addr) mono_thread_info_tls_set (info, TLS_KEY_LMF_ADDR, lmf_addr); } +/* + * mono_push_lmf: + * + * Push an MonoLMFExt frame on the LMF stack. + */ +void +mono_push_lmf (MonoLMFExt *ext) +{ +#ifdef MONO_ARCH_HAVE_INIT_LMF_EXT + MonoLMF **lmf_addr; + + lmf_addr = mono_get_lmf_addr (); + + mono_arch_init_lmf_ext (ext, *lmf_addr); + + mono_set_lmf ((MonoLMF*)ext); +#else + NOT_IMPLEMENTED; +#endif +} + +/* + * mono_push_lmf: + * + * Pop the last frame from the LMF stack. + */ +void +mono_pop_lmf (MonoLMF *lmf) +{ + mono_set_lmf ((MonoLMF *)(((gssize)lmf->previous_lmf) & ~3)); +} + /* * mono_jit_thread_attach: * diff --git a/mono/mini/mini.h b/mono/mini/mini.h index e33dcf85d7f..8e830f91f9d 100644 --- a/mono/mini/mini.h +++ b/mono/mini/mini.h @@ -1216,7 +1216,10 @@ typedef struct { typedef struct { struct MonoLMF lmf; gboolean debugger_invoke; + gboolean interp_exit; MonoContext ctx; /* if debugger_invoke is TRUE */ + /* If interp_exit is TRUE */ + gpointer interp_exit_data; } MonoLMFExt; /* Generic sharing */ @@ -2435,6 +2438,8 @@ gpointer mono_jit_compile_method_inner (MonoMethod *method, MonoDomain *tar MonoLMF * mono_get_lmf (void); MonoLMF** mono_get_lmf_addr (void); void mono_set_lmf (MonoLMF *lmf); +void mono_push_lmf (MonoLMFExt *ext); +void mono_pop_lmf (MonoLMF *lmf); MonoJitTlsData* mono_get_jit_tls (void); MONO_API MonoDomain* mono_jit_thread_attach (MonoDomain *domain); MONO_API void mono_jit_set_domain (MonoDomain *domain); diff --git a/mono/mini/mixed.cs b/mono/mini/mixed.cs index be88673cb18..568589ebe27 100644 --- a/mono/mini/mixed.cs +++ b/mono/mini/mixed.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; using System.Reflection; using System.Runtime.InteropServices; using System.Runtime.CompilerServices; +using System.Diagnostics; /* * Regression tests for the mixed-mode execution. @@ -73,6 +74,16 @@ class InterpClass return i; } + [MethodImplAttribute (MethodImplOptions.NoInlining)] + public static StackTrace get_stacktrace_interp () { + var o = new object (); + return new StackTrace (true); + } + + [MethodImplAttribute (MethodImplOptions.NoInlining)] + public static void throw_ex () { + JitClass.throw_ex (); + } } /* The methods in this class will always be JITted */ @@ -140,6 +151,16 @@ class JitClass public static void exit_byref (ref int i) { i += 1; } + + [MethodImplAttribute (MethodImplOptions.NoInlining)] + public static void throw_ex () { + throw new Exception (); + } + + [MethodImplAttribute (MethodImplOptions.NoInlining)] + public static StackTrace get_stacktrace_jit () { + return InterpClass.get_stacktrace_interp (); + } } #if __MOBILE__ @@ -179,4 +200,64 @@ class Tests return 4; return 0; } + + public static int test_0_throw () { + // Throw an exception from jitted code, catch it in interpreted code + try { + JitClass.throw_ex (); + } catch { + return 0; + } + return 1; + } + + public static int test_0_throw_child () { + try { + InterpClass.throw_ex (); + } catch { + return 0; + } + return 1; + } + + static bool finally_called; + + public static void call_finally () { + try { + JitClass.throw_ex (); + } finally { + finally_called = true; + } + } + + public static int test_0_eh2 () { + finally_called = false; + + // Throw an exception from jitted code, execute finally in interpreted code + try { + call_finally (); + } catch { + return 0; + } + if (!finally_called) + return 2; + return 1; + } + + public static int test_0_stack_traces () { + // + // Get a stacktrace for an interp->jit->interp call stack + // + StackTrace st = JitClass.get_stacktrace_jit (); + var frame = st.GetFrame (0); + if (frame.GetMethod ().Name != "get_stacktrace_interp") + return 1; + frame = st.GetFrame (1); + if (frame.GetMethod ().Name != "get_stacktrace_jit") + return 2; + frame = st.GetFrame (2); + if (frame.GetMethod ().Name != "test_0_stack_traces") + return 3; + return 0; + } } \ No newline at end of file diff --git a/mono/utils/mono-stack-unwinding.h b/mono/utils/mono-stack-unwinding.h index 8a6e1aa244e..82f6127a8a6 100644 --- a/mono/utils/mono-stack-unwinding.h +++ b/mono/utils/mono-stack-unwinding.h @@ -22,7 +22,11 @@ typedef enum { /* Frame for transitioning to native code */ FRAME_TYPE_MANAGED_TO_NATIVE = 2, FRAME_TYPE_TRAMPOLINE = 3, - FRAME_TYPE_NUM = 4 + /* Interpreter frame */ + FRAME_TYPE_INTERP = 4, + /* Frame for transitioning from interpreter to managed code */ + FRAME_TYPE_INTERP_TO_MANAGED = 5, + FRAME_TYPE_NUM = 6 } MonoStackFrameType; typedef enum { @@ -74,6 +78,12 @@ typedef struct { */ int il_offset; + /* For FRAME_TYPE_INTERP_EXIT */ + gpointer interp_exit_data; + + /* For FRAME_TYPE_INTERP */ + gpointer interp_frame; + /* The next fields are only useful for the jit */ gpointer lmf; guint32 unwind_info_len; diff --git a/packaging/MacSDK/packaging/resources/whitelist.txt b/packaging/MacSDK/packaging/resources/whitelist.txt index fadd743d457..e18d5a4cf6d 100644 --- a/packaging/MacSDK/packaging/resources/whitelist.txt +++ b/packaging/MacSDK/packaging/resources/whitelist.txt @@ -14,6 +14,7 @@ certmgr cert-sync chktrust ClassInitGenerator +csc csharp csharp2 dbsessmgr