Interp sdb (#4911)
authorZoltan Varga <vargaz@gmail.com>
Sat, 27 May 2017 16:29:56 +0000 (12:29 -0400)
committerGitHub <noreply@github.com>
Sat, 27 May 2017 16:29:56 +0000 (12:29 -0400)
* [interpreter] Add beginnings of debugger support.

Handle debugger support similarly to the JIT:
- Add a MINT_SDB_SEQ_POINT instruction to the debugger IR. Replace it with a MINT_BREAKPOINT instruction when a breakpoint is placed.
- Store the sequence point information in the existing sequence point data structures.

* [interp] Add support for debugger stacktraces.

* [interp] Add support for debugger frame info.

* [interp] Connect seq points inside the same basic block so simple single stepping works.

* [interp] Link sequence points in different basic blocks the same way the JIT does it.

* [interp] Allocate some bitsets from a mempool.

* [interp] Rewrite the patching in the transform pass to make it a bit easier to understand.

* [interp] Add interruption support for sdb.

* [interp] Add support for mkrefany,refanytype and refanyval.

* [interp] Fix debugger failures.

* Add support for setting byref variables.
* Fix thread interruption when the top frame is an interpreter frame.
* Allow stack walks when a thread is suspended while transforming a method.
* Implement method entry/exit events.
* Fix ldstr+dynamic methods.

* [interp] Implement support for Debugger.Break.

* [interp] Change the offsets in MonoJitInfo/seq points into byte based from short based to reduce the amount of special casing needed in other parts of the code.

* [interp] Factor out the push/pop lmf code into a pair of helper functions.

* [mixed] Fix mixed mode EH.

* [interp] Implement support for MONO_VERBOSE_METHOD. Improve sequence point placement.

* [interp] Implement support for SetIP ().

Pass the target thread as an additional argument to mono_interp_set_resume_state (). Check the resume state after single
stepping/breakpoints in the interpreter.

* [interp] Disable the usage of the STLOC_NP opcodes when running under the debugger, it doesn't work if the ip is changed when the execution is stopped.

* [interp] Fix async stack walks in the debugger when the thread is in native code called from interpreter code.

* [interp] Fix the disable interpreter build.

* [interp] Fix the calculation of native offsets in the line number info.

* [interp] Fix the build.

* [interp] Make CMD_STACK_FRAME_GET_THIS behave the same when called on managed-to-native frames, with the interpreter, frame->has_ctx is set.

* [interp] Fix typos, remove some dead code, use g_print instead of printf in a few places, move some interpreter stubs to interp-stubs.c.

17 files changed:
mono/metadata/domain-internals.h
mono/metadata/mempool-internals.h
mono/mini/Makefile.am.in
mono/mini/debugger-agent.c
mono/mini/interp/interp-internals.h
mono/mini/interp/interp-stubs.c [new file with mode: 0644]
mono/mini/interp/interp.c
mono/mini/interp/interp.h
mono/mini/interp/mintops.c
mono/mini/interp/mintops.def
mono/mini/interp/transform.c
mono/mini/method-to-ir.c
mono/mini/mini-exceptions.c
mono/mini/mini-runtime.c
mono/mini/mini.h
msvc/libmono-static.vcxproj
msvc/libmono-static.vcxproj.filters

index c9fb4add3dd46edb349dc33e980c637972a8d059..6efe5f5a656f4e3ffc711e200ec39b1e9fa2c3d7 100644 (file)
@@ -241,6 +241,8 @@ struct _MonoJitInfo {
         * d.tramp_info contains additional data in this case.
         */
        gboolean    is_trampoline:1;
+       /* Whenever this jit info refers to an interpreter method */
+       gboolean    is_interp:1;
 
        /* FIXME: Embed this after the structure later*/
        gpointer    gc_info; /* Currently only used by SGen */
index d2cf14781b077e8f00e6371770e1996bdb0c3f7f..3458232139c4d3a83dac251c024476ef30e19fd8 100644 (file)
@@ -61,6 +61,20 @@ g_slist_append_mempool (MonoMemPool *mp, GSList *list, gpointer data)
                return new_list;
 }
 
+static inline GList*
+g_list_append_mempool (MonoMemPool *mp, GList *list, gpointer data)
+{
+       GList *new_list;
+
+       new_list = (GList *) mono_mempool_alloc0 (mp, sizeof (GList));
+       new_list->data = data;
+       new_list->prev = g_list_last (list);
+       if (new_list->prev)
+               new_list->prev->next = new_list;
+
+       return list ? list : new_list;
+}
+
 char*
 mono_mempool_strdup_vprintf (MonoMemPool *pool, const char *format, va_list args);
 
index a0bd48867c388d95b3c4c9b46c877668a8d342b7..a08d93b4137fe71b2f60d77b25010a51bd3d5638 100755 (executable)
@@ -401,6 +401,9 @@ interp_sources =    \
        interp/mintops.def      \
        interp/mintops.c        \
        interp/transform.c
+else
+interp_sources = \
+       interp/interp-stubs.c
 endif
 
 if ENABLE_LLVM
index c639fa9e756e5c095b0e73f81b1c78b94651d6a8..bfdddb37547e5dac5d9f4f094b1084d87b359826 100644 (file)
 #include <mono/utils/mono-threads.h>
 #include <mono/utils/networking.h>
 #include <mono/utils/mono-proclib.h>
+#include <mono/utils/w32api.h>
 #include "debugger-agent.h"
 #include "mini.h"
 #include "seq-points.h"
-#include <mono/utils/w32api.h>
+#include "interp/interp.h"
 
 /*
  * On iOS we can't use System.Environment.Exit () as it will do the wrong
@@ -137,6 +138,7 @@ typedef struct
        MonoContext ctx;
        MonoDebugMethodJitInfo *jit;
        MonoJitInfo *ji;
+       MonoInterpFrameHandle interp_frame;
        int flags;
        mgreg_t *reg_locations [MONO_MAX_IREGS];
        /*
@@ -2480,6 +2482,35 @@ static void invoke_method (void);
  * SUSPEND/RESUME
  */
 
+static MonoJitInfo*
+get_top_method_ji (gpointer ip, MonoDomain **domain, gpointer *out_ip)
+{
+       MonoJitInfo *ji;
+
+       if (out_ip)
+               *out_ip = ip;
+
+       ji = mini_jit_info_table_find (mono_domain_get (), (char*)ip, domain);
+       if (!ji) {
+               /* Could be an interpreter method */
+
+               MonoLMF *lmf = mono_get_lmf ();
+               MonoInterpFrameHandle *frame;
+
+               g_assert (((guint64)lmf->previous_lmf) & 2);
+               MonoLMFExt *ext = (MonoLMFExt*)lmf;
+
+               g_assert (ext->interp_exit);
+               frame = ext->interp_exit_data;
+               ji = mono_interp_frame_get_jit_info (frame);
+               if (domain)
+                       *domain = mono_domain_get ();
+               if (out_ip)
+                       *out_ip = mono_interp_frame_get_ip (frame);
+       }
+       return ji;
+}
+
 /*
  * save_thread_context:
  *
@@ -2619,13 +2650,23 @@ thread_interrupt (DebuggerTlsData *tls, MonoThreadInfo *info, MonoJitInfo *ji)
                         * suspended when it returns to managed code, so the parent's ctx should
                         * remain valid.
                         */
+                       MonoThreadUnwindState *state = mono_thread_info_get_suspend_state (info);
+
                        data.last_frame_set = FALSE;
-                       mono_get_eh_callbacks ()->mono_walk_stack_with_state (get_last_frame, mono_thread_info_get_suspend_state (info), MONO_UNWIND_SIGNAL_SAFE, &data);
+                       mono_get_eh_callbacks ()->mono_walk_stack_with_state (get_last_frame, state, MONO_UNWIND_SIGNAL_SAFE, &data);
                        if (data.last_frame_set) {
                                gpointer jit_tls = ((MonoThreadInfo*)tls->thread->thread_info)->jit_data;
 
                                memcpy (&tls->async_last_frame, &data.last_frame, sizeof (StackFrameInfo));
 
+                               if (data.last_frame.type == FRAME_TYPE_INTERP_TO_MANAGED) {
+                                       /*
+                                        * Store the current lmf instead of the parent one, since that
+                                        * contains the interp exit data.
+                                        */
+                                       data.lmf = state->unwind_data [MONO_UNWIND_DATA_LMF];
+                               }
+
                                copy_unwind_state_from_frame_data (&tls->async_state, &data, jit_tls);
                                copy_unwind_state_from_frame_data (&tls->context, &data, jit_tls);
                        } else {
@@ -2751,8 +2792,8 @@ process_suspend (DebuggerTlsData *tls, MonoContext *ctx)
                return;
        }
 
-       ji = mini_jit_info_table_find (mono_domain_get (), (char*)ip, NULL);
-
+       ji = get_top_method_ji (ip, NULL, NULL);
+       g_assert (ji);
        /* Can't suspend in these methods */
        method = jinfo_get_method (ji);
        if (method->klass == mono_defaults.string_class && (!strcmp (method->name, "memset") || strstr (method->name, "memcpy")))
@@ -3051,7 +3092,7 @@ process_frame (StackFrameInfo *info, MonoContext *ctx, gpointer user_data)
        SeqPoint sp;
        int flags = 0;
 
-       if (info->type != FRAME_TYPE_MANAGED) {
+       if (info->type != FRAME_TYPE_MANAGED && info->type != FRAME_TYPE_INTERP) {
                if (info->type == FRAME_TYPE_DEBUGGER_INVOKE) {
                        /* Mark the last frame as an invoke frame */
                        if (ud->frames)
@@ -3104,6 +3145,7 @@ process_frame (StackFrameInfo *info, MonoContext *ctx, gpointer user_data)
        frame->native_offset = info->native_offset;
        frame->flags = flags;
        frame->ji = info->ji;
+       frame->interp_frame = info->interp_frame;
        if (info->reg_locations)
                memcpy (frame->reg_locations, info->reg_locations, MONO_MAX_IREGS * sizeof (mgreg_t*));
        if (ctx) {
@@ -4096,7 +4138,7 @@ jit_end (MonoProfiler *prof, MonoMethod *method, MonoJitInfo *jinfo, int result)
 
        send_type_load (method->klass);
 
-       if (!result)
+       if (!result && jinfo)
                add_pending_breakpoints (method, jinfo);
 }
 
@@ -4229,11 +4271,15 @@ insert_breakpoint (MonoSeqPointInfo *seq_points, MonoDomain *domain, MonoJitInfo
        if (it.seq_point.native_offset == SEQ_POINT_NATIVE_OFFSET_DEAD_CODE) {
                DEBUG_PRINTF (1, "[dbg] Attempting to insert seq point at dead IL offset %d, ignoring.\n", (int)bp->il_offset);
        } else if (count == 0) {
+               if (ji->is_interp) {
+                       mono_interp_set_breakpoint (ji, inst->ip);
+               } else {
 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
-               mono_arch_set_breakpoint (ji, inst->ip);
+                       mono_arch_set_breakpoint (ji, inst->ip);
 #else
-               NOT_IMPLEMENTED;
+                       NOT_IMPLEMENTED;
 #endif
+               }
        }
 
        DEBUG_PRINTF (1, "[dbg] Inserted breakpoint at %s:[il=0x%x,native=0x%x] [%p](%d).\n", mono_method_full_name (jinfo_get_method (ji), TRUE), (int)it.seq_point.il_offset, (int)it.seq_point.native_offset, inst->ip, count);
@@ -4255,7 +4301,10 @@ remove_breakpoint (BreakpointInstance *inst)
        g_assert (count > 0);
 
        if (count == 1 && inst->native_offset != SEQ_POINT_NATIVE_OFFSET_DEAD_CODE) {
-               mono_arch_clear_breakpoint (ji, ip);
+               if (ji->is_interp)
+                       mono_interp_clear_breakpoint (ji, ip);
+               else
+                       mono_arch_clear_breakpoint (ji, ip);
                DEBUG_PRINTF (1, "[dbg] Clear breakpoint at %s [%p].\n", mono_method_full_name (jinfo_get_method (ji), TRUE), ip);
        }
 #else
@@ -4372,12 +4421,15 @@ set_bp_in_method (MonoDomain *domain, MonoMethod *method, MonoSeqPointInfo *seq_
                /* Might be AOTed code */
                mono_class_init (method->klass);
                code = mono_aot_get_method_checked (domain, method, &oerror);
-               g_assert (code);
-               mono_error_assert_ok (&oerror);
-               ji = mono_jit_info_table_find (domain, (char *)code);
+               if (code) {
+                       mono_error_assert_ok (&oerror);
+                       ji = mono_jit_info_table_find (domain, (char *)code);
+               } else {
+                       /* Might be interpreted */
+                       ji = mono_interp_find_jit_info (domain, method);
+               }
                g_assert (ji);
        }
-       g_assert (code);
 
        insert_breakpoint (seq_points, domain, ji, bp, error);
 }
@@ -4636,16 +4688,15 @@ ss_update (SingleStepReq *req, MonoJitInfo *ji, SeqPoint *sp, DebuggerTlsData *t
                }
        }
 
-       MonoDebugMethodAsyncInfo* asyncMethod = mono_debug_lookup_method_async_debug_info (method);
-       if (asyncMethod) {
-               for (int i = 0; i < asyncMethod->num_awaits; i++)
-               {
-                       if (asyncMethod->yield_offsets[i] == sp->il_offset || asyncMethod->resume_offsets[i] == sp->il_offset) {
-                               mono_debug_free_method_async_debug_info (asyncMethod);
+       MonoDebugMethodAsyncInfo* async_method = mono_debug_lookup_method_async_debug_info (method);
+       if (async_method) {
+               for (int i = 0; i < async_method->num_awaits; i++) {
+                       if (async_method->yield_offsets[i] == sp->il_offset || async_method->resume_offsets[i] == sp->il_offset) {
+                               mono_debug_free_method_async_debug_info (async_method);
                                return FALSE;
                        }
                }
-               mono_debug_free_method_async_debug_info (asyncMethod);
+               mono_debug_free_method_async_debug_info (async_method);
        }
 
        if (req->size != STEP_SIZE_LINE)
@@ -4756,7 +4807,7 @@ get_notify_debugger_of_wait_completion_method ()
 }
 
 static void
-process_breakpoint_inner (DebuggerTlsData *tls, gboolean from_signal)
+process_breakpoint (DebuggerTlsData *tls, gboolean from_signal)
 {
        MonoJitInfo *ji;
        guint8 *ip;
@@ -4777,11 +4828,27 @@ process_breakpoint_inner (DebuggerTlsData *tls, gboolean from_signal)
 
        ip = (guint8 *)MONO_CONTEXT_GET_IP (ctx);
        ji = mini_jit_info_table_find (mono_domain_get (), (char*)ip, NULL);
+
+       if (!ji) {
+               /* Interpreter */
+               // FIXME: Pass a flag instead to detect this
+               MonoLMF *lmf = mono_get_lmf ();
+               MonoInterpFrameHandle *frame;
+
+               g_assert (((guint64)lmf->previous_lmf) & 2);
+               MonoLMFExt *ext = (MonoLMFExt*)lmf;
+
+               g_assert (ext->interp_exit);
+               frame = ext->interp_exit_data;
+               ji = mono_interp_frame_get_jit_info (frame);
+               ip = mono_interp_frame_get_ip (frame);
+       }
+
        g_assert (ji && !ji->is_trampoline);
        method = jinfo_get_method (ji);
 
        /* Compute the native offset of the breakpoint from the ip */
-       native_offset = ip - (guint8*)ji->code_start;   
+       native_offset = ip - (guint8*)ji->code_start;
 
        /* 
         * Skip the instruction causing the breakpoint signal.
@@ -4936,9 +5003,9 @@ process_signal_event (void (*func) (DebuggerTlsData*, gboolean))
 }
 
 static void
-process_breakpoint (void)
+process_breakpoint_from_signal (void)
 {
-       process_signal_event (process_breakpoint_inner);
+       process_signal_event (process_breakpoint);
 }
 
 static void
@@ -4980,19 +5047,30 @@ mono_debugger_agent_breakpoint_hit (void *sigctx)
         * problems, like the original signal is disabled, libgc can't handle altstack, etc.
         * So set up the signal context to return to the real breakpoint handler function.
         */
-       resume_from_signal_handler (sigctx, process_breakpoint);
+       resume_from_signal_handler (sigctx, process_breakpoint_from_signal);
 }
 
+typedef struct {
+       gboolean found;
+       MonoContext *ctx;
+} UserBreakCbData;
+
 static gboolean
-user_break_cb (StackFrameInfo *frame, MonoContext *ctx, gpointer data)
+user_break_cb (StackFrameInfo *frame, MonoContext *ctx, gpointer user_data)
 {
+       UserBreakCbData *data = user_data;
+
+       if (frame->type == FRAME_TYPE_INTERP_TO_MANAGED) {
+               data->found = TRUE;
+               return TRUE;
+       }
        if (frame->managed) {
-               *(MonoContext*)data = *ctx;
+               data->found = TRUE;
+               *data->ctx = *ctx;
 
                return TRUE;
-       } else {
-               return FALSE;
        }
+       return FALSE;
 }
 
 /*
@@ -5005,11 +5083,15 @@ mono_debugger_agent_user_break (void)
                MonoContext ctx;
                int suspend_policy;
                GSList *events;
+               UserBreakCbData data;
+
+               memset (&data, 0, sizeof (UserBreakCbData));
+               data.ctx = &ctx;
 
                /* Obtain a context */
                MONO_CONTEXT_SET_IP (&ctx, NULL);
-               mono_walk_stack_with_ctx (user_break_cb, NULL, (MonoUnwindOptions)0, &ctx);
-               g_assert (MONO_CONTEXT_GET_IP (&ctx) != NULL);
+               mono_walk_stack_with_ctx (user_break_cb, NULL, (MonoUnwindOptions)0, &data);
+               g_assert (data.found);
 
                mono_loader_lock ();
                events = create_event_list (EVENT_KIND_USER_BREAK, NULL, NULL, NULL, &suspend_policy);
@@ -5051,8 +5133,6 @@ process_single_step_inner (DebuggerTlsData *tls, gboolean from_signal)
        SeqPoint sp;
        MonoSeqPointInfo *info;
 
-       ip = (guint8 *)MONO_CONTEXT_GET_IP (ctx);
-
        /* Skip the instruction causing the single step */
        if (from_signal)
                mono_arch_skip_single_step (ctx);
@@ -5072,14 +5152,15 @@ process_single_step_inner (DebuggerTlsData *tls, gboolean from_signal)
        if (mono_thread_internal_current () != ss_req->thread)
                return;
 
-       if (log_level > 0) {
-               ji = mini_jit_info_table_find (mono_domain_get (), (char*)ip, &domain);
+       ip = (guint8 *)MONO_CONTEXT_GET_IP (ctx);
+
+       ji = get_top_method_ji (ip, &domain, (gpointer*)&ip);
+       g_assert (ji && !ji->is_trampoline);
 
+       if (log_level > 0) {
                DEBUG_PRINTF (1, "[%p] Single step event (depth=%s) at %s (%p)[0x%x], sp %p, last sp %p\n", (gpointer) (gsize) mono_native_thread_id_get (), ss_depth_to_string (ss_req->depth), mono_method_full_name (jinfo_get_method (ji), TRUE), MONO_CONTEXT_GET_IP (ctx), (int)((guint8*)MONO_CONTEXT_GET_IP (ctx) - (guint8*)ji->code_start), MONO_CONTEXT_GET_SP (ctx), ss_req->last_sp);
        }
 
-       ji = mini_jit_info_table_find (mono_domain_get (), (char*)ip, &domain);
-       g_assert (ji && !ji->is_trampoline);
        method = jinfo_get_method (ji);
        g_assert (method);
 
@@ -5114,8 +5195,10 @@ process_single_step_inner (DebuggerTlsData *tls, gboolean from_signal)
         * The ip points to the instruction causing the single step event, which is before
         * the offset recorded in the seq point map, so find the next seq point after ip.
         */
-       if (!mono_find_next_seq_point_for_native_offset (domain, method, (guint8*)ip - (guint8*)ji->code_start, &info, &sp))
+       if (!mono_find_next_seq_point_for_native_offset (domain, method, (guint8*)ip - (guint8*)ji->code_start, &info, &sp)) {
+               g_assert_not_reached ();
                return;
+       }
 
        il_offset = sp.il_offset;
 
@@ -5230,7 +5313,7 @@ debugger_agent_breakpoint_from_context (MonoContext *ctx)
        mono_thread_state_init_from_monoctx (&tls->restore_state, ctx);
        memcpy (&tls->handler_ctx, ctx, sizeof (MonoContext));
 
-       process_breakpoint_inner (tls, FALSE);
+       process_breakpoint (tls, FALSE);
 
        memcpy (ctx, &tls->restore_state.ctx, sizeof (MonoContext));
        memcpy (&tls->restore_state, &orig_restore_state, sizeof (MonoThreadUnwindState));
@@ -5250,8 +5333,10 @@ start_single_stepping (void)
 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
        int val = InterlockedIncrement (&ss_count);
 
-       if (val == 1)
+       if (val == 1) {
                mono_arch_start_single_stepping ();
+               mono_interp_start_single_stepping ();
+       }
 #else
        g_assert_not_reached ();
 #endif
@@ -5263,8 +5348,10 @@ stop_single_stepping (void)
 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
        int val = InterlockedDecrement (&ss_count);
 
-       if (val == 0)
+       if (val == 0) {
                mono_arch_stop_single_stepping ();
+               mono_interp_stop_single_stepping ();
+       }
 #else
        g_assert_not_reached ();
 #endif
@@ -6707,6 +6794,24 @@ set_var (MonoType *t, MonoDebugVarInfo *var, MonoContext *ctx, MonoDomain *domai
        }
 }
 
+static void
+set_interp_var (MonoType *t, gpointer addr, guint8 *val_buf)
+{
+       int size;
+
+       if (t->byref) {
+               addr = *(gpointer*)addr;
+               g_assert (addr);
+       }
+
+       if (MONO_TYPE_IS_REFERENCE (t))
+               size = sizeof (gpointer);
+       else
+               size = mono_class_value_size (mono_class_from_mono_type (t), NULL);
+
+       memcpy (addr, val_buf, size);
+}
+
 static void
 clear_event_request (int req_id, int etype)
 {
@@ -9376,7 +9481,13 @@ thread_commands (int command, guint8 *p, guint8 *end, Buffer *buf)
                // FIXME: Check that the ip change is safe
 
                DEBUG_PRINTF (1, "[dbg] Setting IP to %s:0x%0x(0x%0x)\n", tls->frames [0]->actual_method->name, (int)sp.il_offset, (int)sp.native_offset);
-               MONO_CONTEXT_SET_IP (&tls->restore_state.ctx, (guint8*)tls->frames [0]->ji->code_start + sp.native_offset);
+
+               if (tls->frames [0]->ji->is_interp) {
+                       MonoJitTlsData *jit_data = ((MonoThreadInfo*)thread->thread_info)->jit_data;
+                       mono_interp_set_resume_state (jit_data, NULL, tls->frames [0]->interp_frame, (guint8*)tls->frames [0]->ji->code_start + sp.native_offset);
+               } else {
+                       MONO_CONTEXT_SET_IP (&tls->restore_state.ctx, (guint8*)tls->frames [0]->ji->code_start + sp.native_offset);
+               }
                break;
        }
        default:
@@ -9442,7 +9553,7 @@ frame_commands (int command, guint8 *p, guint8 *end, Buffer *buf)
 
        sig = mono_method_signature (frame->actual_method);
 
-       if (!jit->has_var_info || !mono_get_seq_points (frame->domain, frame->actual_method))
+       if (!(jit->has_var_info || frame->ji->is_interp) || !mono_get_seq_points (frame->domain, frame->actual_method))
                /*
                 * The method is probably from an aot image compiled without soft-debug, variables might be dead, etc.
                 */
@@ -9463,9 +9574,17 @@ frame_commands (int command, guint8 *p, guint8 *end, Buffer *buf)
 
                                DEBUG_PRINTF (4, "[dbg]   send arg %d.\n", pos);
 
-                               g_assert (pos >= 0 && pos < jit->num_params);
+                               if (frame->ji->is_interp) {
+                                       guint8 *addr;
+
+                                       addr = mono_interp_frame_get_arg (frame->interp_frame, pos);
+
+                                       buffer_add_value_full (buf, sig->params [pos], addr, frame->domain, FALSE, NULL);
+                               } else {
+                                       g_assert (pos >= 0 && pos < jit->num_params);
 
-                               add_var (buf, jit, sig->params [pos], &jit->params [pos], &frame->ctx, frame->domain, FALSE);
+                                       add_var (buf, jit, sig->params [pos], &jit->params [pos], &frame->ctx, frame->domain, FALSE);
+                               }
                        } else {
                                MonoDebugLocalsInfo *locals;
 
@@ -9475,30 +9594,57 @@ frame_commands (int command, guint8 *p, guint8 *end, Buffer *buf)
                                        pos = locals->locals [pos].index;
                                        mono_debug_free_locals (locals);
                                }
-                               g_assert (pos >= 0 && pos < jit->num_locals);
 
                                DEBUG_PRINTF (4, "[dbg]   send local %d.\n", pos);
 
-                               add_var (buf, jit, header->locals [pos], &jit->locals [pos], &frame->ctx, frame->domain, FALSE);
+                               if (frame->ji->is_interp) {
+                                       guint8 *addr;
+
+                                       addr = mono_interp_frame_get_local (frame->interp_frame, pos);
+
+                                       buffer_add_value_full (buf, header->locals [pos], addr, frame->domain, FALSE, NULL);
+                               } else {
+                                       g_assert (pos >= 0 && pos < jit->num_locals);
+
+                                       add_var (buf, jit, header->locals [pos], &jit->locals [pos], &frame->ctx, frame->domain, FALSE);
+                               }
                        }
                }
                mono_metadata_free_mh (header);
                break;
        }
        case CMD_STACK_FRAME_GET_THIS: {
+               if (frame->method->wrapper_type == MONO_WRAPPER_MANAGED_TO_NATIVE)
+                       return ERR_ABSENT_INFORMATION;
                if (frame->api_method->klass->valuetype) {
                        if (!sig->hasthis) {
                                MonoObject *p = NULL;
                                buffer_add_value (buf, &mono_defaults.object_class->byval_arg, &p, frame->domain);
                        } else {
-                               add_var (buf, jit, &frame->actual_method->klass->this_arg, jit->this_var, &frame->ctx, frame->domain, TRUE);
+                               if (frame->ji->is_interp) {
+                                       guint8 *addr;
+
+                                       addr = mono_interp_frame_get_this (frame->interp_frame);
+
+                                       buffer_add_value_full (buf, &frame->actual_method->klass->this_arg, addr, frame->domain, FALSE, NULL);
+                               } else {
+                                       add_var (buf, jit, &frame->actual_method->klass->this_arg, jit->this_var, &frame->ctx, frame->domain, TRUE);
+                               }
                        }
                } else {
                        if (!sig->hasthis) {
                                MonoObject *p = NULL;
                                buffer_add_value (buf, &frame->actual_method->klass->byval_arg, &p, frame->domain);
                        } else {
-                               add_var (buf, jit, &frame->api_method->klass->byval_arg, jit->this_var, &frame->ctx, frame->domain, TRUE);
+                               if (frame->ji->is_interp) {
+                                       guint8 *addr;
+
+                                       addr = mono_interp_frame_get_this (frame->interp_frame);
+
+                                       buffer_add_value_full (buf, &frame->api_method->klass->byval_arg, addr, frame->domain, FALSE, NULL);
+                               } else {
+                                       add_var (buf, jit, &frame->api_method->klass->byval_arg, jit->this_var, &frame->ctx, frame->domain, TRUE);
+                               }
                        }
                }
                break;
@@ -9507,7 +9653,8 @@ frame_commands (int command, guint8 *p, guint8 *end, Buffer *buf)
                MonoError error;
                guint8 *val_buf;
                MonoType *t;
-               MonoDebugVarInfo *var;
+               MonoDebugVarInfo *var = NULL;
+               gboolean is_arg = FALSE;
 
                len = decode_int (p, &p, end);
                header = mono_method_get_header_checked (frame->actual_method, &error);
@@ -9523,6 +9670,7 @@ frame_commands (int command, guint8 *p, guint8 *end, Buffer *buf)
 
                                t = sig->params [pos];
                                var = &jit->params [pos];
+                               is_arg = TRUE;
                        } else {
                                MonoDebugLocalsInfo *locals;
 
@@ -9546,7 +9694,17 @@ frame_commands (int command, guint8 *p, guint8 *end, Buffer *buf)
                        if (err != ERR_NONE)
                                return err;
 
-                       set_var (t, var, &frame->ctx, frame->domain, val_buf, frame->reg_locations, &tls->restore_state.ctx);
+                       if (frame->ji->is_interp) {
+                               guint8 *addr;
+
+                               if (is_arg)
+                                       addr = mono_interp_frame_get_arg (frame->interp_frame, pos);
+                               else
+                                       addr = mono_interp_frame_get_local (frame->interp_frame, pos);
+                               set_interp_var (t, addr, val_buf);
+                       } else {
+                               set_var (t, var, &frame->ctx, frame->domain, val_buf, frame->reg_locations, &tls->restore_state.ctx);
+                       }
                }
                mono_metadata_free_mh (header);
                break;
@@ -9564,15 +9722,23 @@ frame_commands (int command, guint8 *p, guint8 *end, Buffer *buf)
                t = &frame->actual_method->klass->byval_arg;
                /* Checked by the sender */
                g_assert (MONO_TYPE_ISSTRUCT (t));
-               var = jit->this_var;
-               g_assert (var);
 
                val_buf = (guint8 *)g_alloca (mono_class_instance_size (mono_class_from_mono_type (t)));
                err = decode_value (t, frame->domain, val_buf, p, &p, end);
                if (err != ERR_NONE)
                        return err;
 
-               set_var (&frame->actual_method->klass->this_arg, var, &frame->ctx, frame->domain, val_buf, frame->reg_locations, &tls->restore_state.ctx);
+               if (frame->ji->is_interp) {
+                       guint8 *addr;
+
+                       addr = mono_interp_frame_get_this (frame->interp_frame);
+                       set_interp_var (&frame->actual_method->klass->this_arg, addr, val_buf);
+               } else {
+                       var = jit->this_var;
+                       g_assert (var);
+
+                       set_var (&frame->actual_method->klass->this_arg, var, &frame->ctx, frame->domain, val_buf, frame->reg_locations, &tls->restore_state.ctx);
+               }
                break;
        }
        default:
index cc4cd237c677f3be75f9b93162979168aef28f7d..3b19a6d1bdaba5b7215c34a9ece4020672d6abf7 100644 (file)
@@ -105,6 +105,7 @@ struct _MonoInvocation {
        stackval       *stack_args; /* parent */
        stackval       *stack;
        stackval       *sp; /* For GC stack marking */
+       unsigned char  *locals;
        /* exception info */
        unsigned char  invoke_trap;
        const unsigned short  *ip;
diff --git a/mono/mini/interp/interp-stubs.c b/mono/mini/interp/interp-stubs.c
new file mode 100644 (file)
index 0000000..176e45b
--- /dev/null
@@ -0,0 +1,98 @@
+#include <config.h>
+
+#ifndef ENABLE_INTERPRETER
+
+#include "interp.h"
+
+/* Dummy versions of interpreter functions to avoid ifdefs at call sites */
+
+MonoJitInfo*
+mono_interp_find_jit_info (MonoDomain *domain, MonoMethod *method)
+{
+       return NULL;
+}
+
+void
+mono_interp_set_breakpoint (MonoJitInfo *jinfo, gpointer ip)
+{
+       g_assert_not_reached ();
+}
+
+void
+mono_interp_clear_breakpoint (MonoJitInfo *jinfo, gpointer ip)
+{
+       g_assert_not_reached ();
+}
+
+MonoJitInfo*
+mono_interp_frame_get_jit_info (MonoInterpFrameHandle frame)
+{
+       g_assert_not_reached ();
+       return NULL;
+}
+
+gpointer
+mono_interp_frame_get_ip (MonoInterpFrameHandle frame)
+{
+       g_assert_not_reached ();
+       return NULL;
+}
+
+gpointer
+mono_interp_frame_get_arg (MonoInterpFrameHandle frame, int pos)
+{
+       g_assert_not_reached ();
+       return NULL;
+}
+
+gpointer
+mono_interp_frame_get_local (MonoInterpFrameHandle frame, int pos)
+{
+       g_assert_not_reached ();
+       return NULL;
+}
+
+gpointer
+mono_interp_frame_get_this (MonoInterpFrameHandle frame)
+{
+       g_assert_not_reached ();
+       return NULL;
+}
+
+void
+mono_interp_start_single_stepping (void)
+{
+}
+
+void
+mono_interp_stop_single_stepping (void)
+{
+}
+
+void
+mono_interp_set_resume_state (MonoJitTlsData *jit_tls, MonoException *ex, MonoInterpFrameHandle interp_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
+
index bea20a44f54c3f8ecc2fc534776564e4720e2e4a..0b530d8330a0b45321f15d8797b1931dc2507e63 100644 (file)
@@ -66,6 +66,7 @@
 
 #include <mono/mini/mini.h>
 #include <mono/mini/jit-icalls.h>
+#include <mono/mini/debugger-agent.h>
 
 #ifdef TARGET_ARM
 #include <mono/mini/mini-arm.h>
@@ -104,6 +105,8 @@ init_frame (MonoInvocation *frame, MonoInvocation *parent_frame, RuntimeMethod *
  * Used for testing.
  */
 GSList *jit_classes;
+/* If TRUE, interpreted code will be interrupted at function entry/backward branches */
+static gboolean ss_enabled;
 
 void ves_exec_method (MonoInvocation *frame);
 
@@ -204,14 +207,27 @@ static void debug_enter (MonoInvocation *frame, int *tracing)
 /* Set the current execution state to the resume state in context */
 #define SET_RESUME_STATE(context) do { \
                ip = (context)->handler_ip;                                             \
+               if (frame->ex) { \
                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
+set_context (ThreadContext *context)
+{
+       MonoJitTlsData *jit_tls;
+
+       mono_native_tls_set_value (thread_context_id, context);
+       jit_tls = mono_tls_get_jit_tls ();
+       if (jit_tls)
+               jit_tls->interp_context = context;
+}
+
 static void
 ves_real_abort (int line, MonoMethod *mh,
                const unsigned short *ip, stackval *stack, stackval *sp)
@@ -234,6 +250,19 @@ ves_real_abort (int line, MonoMethod *mh,
                THROW_EX (mono_get_exception_execution_engine (NULL), ip); \
        } while (0);
 
+static RuntimeMethod*
+lookup_runtime_method (MonoDomain *domain, MonoMethod *method)
+{
+       RuntimeMethod *rtm;
+       MonoJitDomainInfo *info;
+
+       info = domain_jit_info (domain);
+       mono_domain_jit_code_hash_lock (domain);
+       rtm = mono_internal_hash_table_lookup (&info->interp_code_hash, method);
+       mono_domain_jit_code_hash_unlock (domain);
+       return rtm;
+}
+
 RuntimeMethod*
 mono_interp_get_runtime_method (MonoDomain *domain, MonoMethod *method, MonoError *error)
 {
@@ -278,6 +307,30 @@ mono_interp_create_trampoline (MonoDomain *domain, MonoMethod *method, MonoError
        return mono_interp_get_runtime_method (domain, method, error);
 }
 
+/*
+ * interp_push_lmf:
+ *
+ * Push an LMF frame on the LMF stack
+ * to mark the transition to native code.
+ * This is needed for the native code to
+ * be able to do stack walks.
+ */
+static void
+interp_push_lmf (MonoLMFExt *ext, MonoInvocation *frame)
+{
+       memset (ext, 0, sizeof (MonoLMFExt));
+       ext->interp_exit = TRUE;
+       ext->interp_exit_data = frame;
+
+       mono_push_lmf (ext);
+}
+
+static void
+interp_pop_lmf (MonoLMFExt *ext)
+{
+       mono_pop_lmf (&ext->lmf);
+}
+
 static inline RuntimeMethod*
 get_virtual_method (MonoDomain *domain, RuntimeMethod *runtime_method, MonoObject *obj)
 {
@@ -943,19 +996,11 @@ 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);
+       interp_push_lmf (&ext, frame);
 
        mono_interp_enter_icall_trampoline (addr, margs);
 
-       mono_pop_lmf (&ext.lmf);
+       interp_pop_lmf (&ext);
 
        context->managed_code = 1;
        /* domain can only be changed by native code */
@@ -1307,7 +1352,7 @@ mono_interp_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoOb
        int i, type, isobject = 0;
        void *ret = NULL;
        stackval result;
-       stackval *args = alloca (sizeof (stackval) * (sig->param_count + !!sig->hasthis));
+       stackval *args;
        ThreadContext context_struct;
        MonoInvocation *old_frame = NULL;
        jmp_buf env;
@@ -1323,8 +1368,8 @@ mono_interp_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoOb
                        context->domain = mono_domain_get ();
                        context->current_frame = old_frame;
                        context->managed_code = 0;
-               } else 
-                       mono_native_tls_set_value (thread_context_id, NULL);
+               } else
+                       set_context (NULL);
                if (exc != NULL)
                        *exc = (MonoObject *)frame.ex;
                return retval;
@@ -1336,7 +1381,7 @@ mono_interp_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoOb
                context_struct.base_frame = &frame;
                context_struct.env_frame = &frame;
                context_struct.current_env = &env;
-               mono_native_tls_set_value (thread_context_id, context);
+               set_context (context);
        }
        else
                old_frame = context->current_frame;
@@ -1384,6 +1429,7 @@ mono_interp_runtime_invoke (MonoMethod *method, void *obj, void **params, MonoOb
                break;
        }
 
+       args = alloca (sizeof (stackval) * (sig->param_count + !!sig->hasthis));
        if (sig->hasthis)
                args [0].data.p = obj;
 
@@ -1453,13 +1499,14 @@ handle_enum:
        if (method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL)
                method = mono_marshal_get_native_wrapper (method, FALSE, FALSE);
        INIT_FRAME (&frame,context->current_frame,args,&result,mono_get_root_domain (),method,error);
+
        if (exc)
                frame.invoke_trap = 1;
        context->managed_code = 1;
        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);
+               set_context (NULL);
        else
                context->current_frame = old_frame;
        if (frame.ex != NULL) {
@@ -1519,10 +1566,10 @@ interp_entry (InterpEntryData *data)
                memset (context, 0, sizeof (ThreadContext));
                context_struct.base_frame = &frame;
                context_struct.env_frame = &frame;
-               mono_native_tls_set_value (thread_context_id, context);
-       }
-       else
+               set_context (context);
+       } else {
                old_frame = context->current_frame;
+       }
        context->domain = mono_domain_get ();
 
        args = alloca (sizeof (stackval) * (sig->param_count + (sig->hasthis ? 1 : 0)));
@@ -1615,7 +1662,7 @@ interp_entry (InterpEntryData *data)
        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);
+               set_context (NULL);
        else
                context->current_frame = old_frame;
 
@@ -2088,8 +2135,17 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context, uns
                g_print ("(%p) Transforming %s\n", mono_thread_internal_current (), mn);
                g_free (mn);
 #endif
+
+               MonoLMFExt ext;
+
+               /* Use the parent frame as the current frame is not complete yet */
+               interp_push_lmf (&ext, frame->parent);
+
                frame->ex = mono_interp_transform_method (frame->runtime_method, context);
                context->managed_code = 1;
+
+               interp_pop_lmf (&ext);
+
                if (frame->ex) {
                        rtm = NULL;
                        ip = NULL;
@@ -2112,6 +2168,7 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context, uns
        vtalloc = vt_sp;
 #endif
        locals = (unsigned char *) vt_sp + rtm->vt_stack_size;
+       frame->locals = locals;
        child_frame.parent = frame;
 
        if (filter_exception) {
@@ -2136,10 +2193,18 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context, uns
                MINT_IN_CASE(MINT_NOP)
                        ++ip;
                        MINT_IN_BREAK;
-               MINT_IN_CASE(MINT_BREAK)
+               MINT_IN_CASE(MINT_BREAK) {
                        ++ip;
-                       G_BREAKPOINT (); /* this is not portable... */
+
+                       MonoLMFExt ext;
+
+                       interp_push_lmf (&ext, frame);
+
+                       mono_debugger_agent_user_break ();
+
+                       interp_pop_lmf (&ext);
                        MINT_IN_BREAK;
+               }
                MINT_IN_CASE(MINT_LDNULL) 
                        sp->data.p = NULL;
                        ++ip;
@@ -2257,6 +2322,7 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context, uns
                        vtalloc = vt_sp;
 #endif
                        locals = vt_sp + rtm->vt_stack_size;
+                       frame->locals = locals;
                        ip = rtm->new_body_start; /* bypass storing input args from callers frame */
                        MINT_IN_BREAK;
                }
@@ -2567,15 +2633,7 @@ 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);
+                       interp_push_lmf (&ext, frame);
 
                        switch (pindex) {
                        case 0: {
@@ -2631,7 +2689,7 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context, uns
                                break;
                        }
 
-                       mono_pop_lmf (&ext.lmf);
+                       interp_pop_lmf (&ext);
 
                        if (context->has_resume_state) {
                                /*
@@ -2819,7 +2877,7 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context, uns
                        goto exit_frame;
                MINT_IN_CASE(MINT_RET_VOID)
                        if (sp > frame->stack)
-                               g_warning ("ret.void: more values on stack: %d", sp-frame->stack);
+                               g_warning ("ret.void: more values on stack: %d %s", sp-frame->stack, mono_method_full_name (frame->runtime_method->method, TRUE));
                        goto exit_frame;
                MINT_IN_CASE(MINT_RET_VT)
                        i32 = READ32(ip + 1);
@@ -3110,7 +3168,7 @@ ves_exec_method_with_context (MonoInvocation *frame, ThreadContext *context, uns
                                gint offset;
                                ip += 2 * (guint32)sp->data.i;
                                offset = READ32 (ip);
-                               ip = st + offset;
+                               ip = ip + offset;
                        } else {
                                ip = st;
                        }
@@ -3664,6 +3722,7 @@ array_constructed:
                        frame->ex_handler = NULL;
                        if (!sp->data.p)
                                sp->data.p = mono_get_exception_null_reference ();
+
                        THROW_EX ((MonoException *)sp->data.p, ip);
                        MINT_IN_BREAK;
                MINT_IN_CASE(MINT_LDFLDA_UNSAFE)
@@ -4516,6 +4575,72 @@ array_constructed:
                        ++ip;
                        mono_jit_set_domain (context->original_domain);
                        MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_SDB_INTR_LOC)
+                       if (G_UNLIKELY (ss_enabled)) {
+                               MonoLMFExt ext;
+                               static void (*ss_tramp) (void);
+
+                               if (!ss_tramp) {
+                                       void *tramp = mini_get_single_step_trampoline ();
+                                       mono_memory_barrier ();
+                                       ss_tramp = tramp;
+                               }
+
+                               /*
+                                * Make this point to the MINT_SDB_SEQ_POINT instruction which follows this since
+                                * the address of that instruction is stored as the seq point address.
+                                */
+                               frame->ip = ip + 1;
+
+                               interp_push_lmf (&ext, frame);
+                               /*
+                                * Use the same trampoline as the JIT. This ensures that
+                                * the debugger has the context for the last interpreter
+                                * native frame.
+                                */
+                               ss_tramp ();
+                               interp_pop_lmf (&ext);
+
+                               if (context->has_resume_state) {
+                                       if (frame == context->handler_frame)
+                                               SET_RESUME_STATE (context);
+                                       else
+                                               goto exit_frame;
+                               }
+                       }
+                       ++ip;
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_SDB_SEQ_POINT)
+                       /* Just a placeholder for a breakpoint */
+                       ++ip;
+                       MINT_IN_BREAK;
+               MINT_IN_CASE(MINT_SDB_BREAKPOINT) {
+                       MonoLMFExt ext;
+
+                       static void (*bp_tramp) (void);
+                       if (!bp_tramp) {
+                               void *tramp = mini_get_breakpoint_trampoline ();
+                               mono_memory_barrier ();
+                               bp_tramp = tramp;
+                       }
+
+                       frame->ip = ip;
+
+                       interp_push_lmf (&ext, frame);
+                       /* Use the same trampoline as the JIT */
+                       bp_tramp ();
+                       interp_pop_lmf (&ext);
+
+                       if (context->has_resume_state) {
+                               if (frame == context->handler_frame)
+                                       SET_RESUME_STATE (context);
+                               else
+                                       goto exit_frame;
+                       }
+
+                       ++ip;
+                       MINT_IN_BREAK;
+               }
 
 #define RELOP(datamem, op) \
        --sp; \
@@ -5061,7 +5186,7 @@ ves_exec_method (MonoInvocation *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);
+               set_context (context);
        }
        frame->ip = NULL;
        frame->parent = context->current_frame;
@@ -5079,7 +5204,7 @@ ves_exec_method (MonoInvocation *frame)
                        mono_unhandled_exception ((MonoObject*)frame->ex);
        }
        if (context->base_frame == frame)
-               mono_native_tls_set_value (thread_context_id, NULL);
+               set_context (NULL);
        else
                context->current_frame = frame->parent;
 }
@@ -5102,7 +5227,7 @@ void
 mono_interp_init ()
 {
        mono_native_tls_alloc (&thread_context_id, NULL);
-       mono_native_tls_set_value (thread_context_id, NULL);
+       set_context (NULL);
 
        mono_interp_transform_init ();
 }
@@ -5278,12 +5403,16 @@ mono_interp_regression_list (int verbose, int count, char *images [])
  *   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)
+mono_interp_set_resume_state (MonoJitTlsData *jit_tls, MonoException *ex, MonoInterpFrameHandle interp_frame, gpointer handler_ip)
 {
-       ThreadContext *context = mono_native_tls_get_value (thread_context_id);
+       ThreadContext *context;
+
+       g_assert (jit_tls);
+       context = jit_tls->interp_context;
+       g_assert (context);
 
        context->has_resume_state = TRUE;
-       context->handler_frame = frame->interp_frame;
+       context->handler_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;
@@ -5329,20 +5458,115 @@ mono_interp_frame_iter_next (MonoInterpStackIter *iter, StackFrameInfo *frame)
 
        memset (frame, 0, sizeof (StackFrameInfo));
        /* pinvoke frames doesn't have runtime_method set */
-       while (iframe && !iframe->runtime_method)
+       while (iframe && !(iframe->runtime_method && iframe->runtime_method->code))
                iframe = iframe->parent;
        if (!iframe)
                return FALSE;
 
        frame->type = FRAME_TYPE_INTERP;
+       // FIXME:
+       frame->domain = mono_domain_get ();
        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->native_offset = (guint8*)iframe->ip - (guint8*)iframe->runtime_method->code;
        frame->ji = iframe->runtime_method->jinfo;
 
        stack_iter->current = iframe->parent;
 
        return TRUE;
 }
+
+MonoJitInfo*
+mono_interp_find_jit_info (MonoDomain *domain, MonoMethod *method)
+{
+       RuntimeMethod* rtm;
+
+       rtm = lookup_runtime_method (domain, method);
+       if (rtm)
+               return rtm->jinfo;
+       else
+               return NULL;
+}
+
+void
+mono_interp_set_breakpoint (MonoJitInfo *jinfo, gpointer ip)
+{
+       guint16 *code = (guint16*)ip;
+       g_assert (*code == MINT_SDB_SEQ_POINT);
+       *code = MINT_SDB_BREAKPOINT;
+}
+
+void
+mono_interp_clear_breakpoint (MonoJitInfo *jinfo, gpointer ip)
+{
+       guint16 *code = (guint16*)ip;
+       g_assert (*code == MINT_SDB_BREAKPOINT);
+       *code = MINT_SDB_SEQ_POINT;
+}
+
+MonoJitInfo*
+mono_interp_frame_get_jit_info (MonoInterpFrameHandle frame)
+{
+       MonoInvocation *iframe = (MonoInvocation*)frame;
+
+       g_assert (iframe->runtime_method);
+       return iframe->runtime_method->jinfo;
+}
+
+gpointer
+mono_interp_frame_get_ip (MonoInterpFrameHandle frame)
+{
+       MonoInvocation *iframe = (MonoInvocation*)frame;
+
+       g_assert (iframe->runtime_method);
+       return (gpointer)iframe->ip;
+}
+
+gpointer
+mono_interp_frame_get_arg (MonoInterpFrameHandle frame, int pos)
+{
+       MonoInvocation *iframe = (MonoInvocation*)frame;
+
+       g_assert (iframe->runtime_method);
+
+       int arg_offset = iframe->runtime_method->arg_offsets [pos + (iframe->runtime_method->hasthis ? 1 : 0)];
+
+       return iframe->args + arg_offset;
+}
+
+gpointer
+mono_interp_frame_get_local (MonoInterpFrameHandle frame, int pos)
+{
+       MonoInvocation *iframe = (MonoInvocation*)frame;
+
+       g_assert (iframe->runtime_method);
+
+       return iframe->locals + iframe->runtime_method->local_offsets [pos];
+}
+
+gpointer
+mono_interp_frame_get_this (MonoInterpFrameHandle frame)
+{
+       MonoInvocation *iframe = (MonoInvocation*)frame;
+
+       g_assert (iframe->runtime_method);
+       g_assert (iframe->runtime_method->hasthis);
+
+       int arg_offset = iframe->runtime_method->arg_offsets [0];
+
+       return iframe->args + arg_offset;
+}
+
+void
+mono_interp_start_single_stepping (void)
+{
+       ss_enabled = TRUE;
+}
+
+void
+mono_interp_stop_single_stepping (void)
+{
+       ss_enabled = FALSE;
+}
index cf922507500bc16adae32d32dd1ed0ccf0283c5f..6abf93a6f0a38c900820258f6b73859f2b35d048 100644 (file)
@@ -28,6 +28,8 @@ struct _MonoInterpStackIter {
        gpointer dummy [8];
 };
 
+typedef gpointer MonoInterpFrameHandle;
+
 int
 mono_interp_regression_list (int verbose, int count, char *images []);
 
@@ -53,7 +55,7 @@ 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);
+mono_interp_set_resume_state (MonoJitTlsData *jit_tls, MonoException *ex, MonoInterpFrameHandle interp_frame, gpointer handler_ip);
 
 void
 mono_interp_run_finally (StackFrameInfo *frame, int clause_index, gpointer handler_ip);
@@ -64,4 +66,34 @@ mono_interp_frame_iter_init (MonoInterpStackIter *iter, gpointer interp_exit_dat
 gboolean
 mono_interp_frame_iter_next (MonoInterpStackIter *iter, StackFrameInfo *frame);
 
+MonoJitInfo*
+mono_interp_find_jit_info (MonoDomain *domain, MonoMethod *method);
+
+void
+mono_interp_set_breakpoint (MonoJitInfo *jinfo, gpointer ip);
+
+void
+mono_interp_clear_breakpoint (MonoJitInfo *jinfo, gpointer ip);
+
+MonoJitInfo*
+mono_interp_frame_get_jit_info (MonoInterpFrameHandle frame);
+
+gpointer
+mono_interp_frame_get_ip (MonoInterpFrameHandle frame);
+
+gpointer
+mono_interp_frame_get_arg (MonoInterpFrameHandle frame, int pos);
+
+gpointer
+mono_interp_frame_get_local (MonoInterpFrameHandle frame, int pos);
+
+gpointer
+mono_interp_frame_get_this (MonoInterpFrameHandle frame);
+
+void
+mono_interp_start_single_stepping (void);
+
+void
+mono_interp_stop_single_stepping (void);
+
 #endif /* __MONO_MINI_INTERPRETER_H__ */
index e1c58ecf7a968643c8ac0ae638088dfa4f4aea01..b0fa6358c894a4ea71e3611569634a8eee56c310 100644 (file)
@@ -106,7 +106,7 @@ mono_interp_dis_mintop(const guint16 *base, const guint16 *ip)
                        if (i > 0)
                                g_print (", ");
                        offset = (gint32)READ32 (p);
-                       g_print ("IL_%04x", ip - base + 3 + 2 * sval + offset);
+                       g_print ("IL_%04x", p + offset);
                        p += 2;
                }
                g_print (")");
index 190c6647d08adef26aee2599bfc0bbe2c2be21e1..647e5838607a5b02433365592919a620f745feb6 100644 (file)
@@ -521,3 +521,6 @@ OPDEF(MINT_MONO_JIT_DETACH, "mono_jit_detach", 1, MintOpNoArgs)
 
 // FIXME: MintOp
 OPDEF(MINT_JIT_CALL, "mono_jit_call", 2, MintOpNoArgs)
+OPDEF(MINT_SDB_INTR_LOC, "sdb_intr_loc", 1, MintOpNoArgs)
+OPDEF(MINT_SDB_SEQ_POINT, "sdb_seq_point", 1, MintOpNoArgs)
+OPDEF(MINT_SDB_BREAKPOINT, "sdb_breakpoint", 1, MintOpNoArgs)
index fb2ef6b60c0e32a599846796fd10c3d74d9ab53e..a309a4a9fab839713de230df79eb0176c92631e1 100644 (file)
@@ -15,6 +15,7 @@
 #include <mono/metadata/marshal.h>
 #include <mono/metadata/profiler-private.h>
 #include <mono/metadata/tabledefs.h>
+#include <mono/metadata/seq-points-data.h>
 
 #include <mono/mini/mini.h>
 
@@ -34,6 +35,31 @@ typedef struct
        unsigned char flags;
 } StackInfo;
 
+typedef struct {
+       guint8 *ip;
+       GSList *preds;
+       GSList *seq_points;
+       SeqPoint *last_seq_point;
+
+       // This will hold a list of last sequence points of incoming basic blocks
+       SeqPoint **pred_seq_points;
+       guint num_pred_seq_points;
+} InterpBasicBlock;
+
+typedef enum {
+       RELOC_SHORT_BRANCH,
+       RELOC_LONG_BRANCH,
+       RELOC_SWITCH
+} RelocType;
+
+typedef struct {
+       RelocType type;
+       /* In the interpreter IR */
+       int offset;
+       /* In the IL code */
+       int target;
+} Reloc;
+
 typedef struct
 {
        MonoMethod *method;
@@ -45,7 +71,6 @@ typedef struct
        const unsigned char *in_start;
        int code_size;
        int *in_offsets;
-       int *forward_refs;
        StackInfo **stack_state;
        int *stack_height;
        int *vt_stack_size;
@@ -65,6 +90,14 @@ typedef struct
        void **data_items;
        GHashTable *data_hash;
        int *clause_indexes;
+       gboolean gen_sdb_seq_points;
+       GPtrArray *seq_points;
+       InterpBasicBlock **offset_to_bb;
+       InterpBasicBlock *entry_bb;
+       MonoMemPool     *mempool;
+       GList *basic_blocks;
+       GPtrArray *relocs;
+       gboolean verbose_level;
 } TransformData;
 
 #define MINT_TYPE_I1 0
@@ -150,7 +183,7 @@ grow_code (TransformData *td)
        } while (0)
 
 static void 
-handle_branch(TransformData *td, int short_op, int long_op, int offset) 
+handle_branch (TransformData *td, int short_op, int long_op, int offset)
 {
        int shorten_branch = 0;
        int target = td->ip + offset - td->il_code;
@@ -168,12 +201,18 @@ handle_branch(TransformData *td, int short_op, int long_op, int offset)
                        shorten_branch = 1;
                }
        } else {
-               int prev = td->forward_refs [target];
-               td->forward_refs [td->ip - td->il_code] = prev;
-               td->forward_refs [target] = td->ip - td->il_code;
-               offset = 0;
+               offset = 0xffff;
                if (td->header->code_size <= 25000) /* FIX to be precise somehow? */
                        shorten_branch = 1;
+
+               Reloc *reloc = mono_mempool_alloc0 (td->mempool, sizeof (Reloc));
+               if (shorten_branch)
+                       reloc->type = RELOC_SHORT_BRANCH;
+               else
+                       reloc->type = RELOC_LONG_BRANCH;
+               reloc->offset = td->new_ip - td->new_code;
+               reloc->target = target;
+               g_ptr_array_add (td->relocs, reloc);
        }
        if (shorten_branch) {
                ADD_CODE(td, short_op);
@@ -554,11 +593,13 @@ load_local(TransformData *td, int n)
                WRITE32(td, &size);
        } else {
                g_assert (mt < MINT_TYPE_VT);
-               if (mt == MINT_TYPE_I4 && !td->is_bb_start [td->in_start - td->il_code] && td->last_new_ip != NULL &&
+               if (!td->gen_sdb_seq_points &&
+                       mt == MINT_TYPE_I4 && !td->is_bb_start [td->in_start - td->il_code] && td->last_new_ip != NULL &&
                        td->last_new_ip [0] == MINT_STLOC_I4 && td->last_new_ip [1] == offset) {
                        td->last_new_ip [0] = MINT_STLOC_NP_I4;
-               } else if (mt == MINT_TYPE_O && !td->is_bb_start [td->in_start - td->il_code] && td->last_new_ip != NULL &&
-                       td->last_new_ip [0] == MINT_STLOC_O && td->last_new_ip [1] == offset) {
+               } else if (!td->gen_sdb_seq_points &&
+                                  mt == MINT_TYPE_O && !td->is_bb_start [td->in_start - td->il_code] && td->last_new_ip != NULL &&
+                                  td->last_new_ip [0] == MINT_STLOC_O && td->last_new_ip [1] == offset) {
                        td->last_new_ip [0] = MINT_STLOC_NP_O;
                } else {
                        ADD_CODE(td, MINT_LDLOC_I1 + (mt - MINT_TYPE_I1));
@@ -696,22 +737,8 @@ interp_transform_call (TransformData *td, MonoMethod *method, MonoMethod *target
                        else
                                target_method = (MonoMethod *)mono_method_get_wrapper_data (method, token);
                        csignature = mono_method_signature (target_method);
-                       if (target_method->klass == mono_defaults.string_class) {
-                               if (target_method->name [0] == 'g') {
-                                       if (strcmp (target_method->name, "get_Chars") == 0)
-                                               op = MINT_GETCHR;
-                                       else if (strcmp (target_method->name, "get_Length") == 0)
-                                               op = MINT_STRLEN;
-                               }
-                       } else if (mono_class_is_subclass_of (target_method->klass, mono_defaults.array_class, FALSE)) {
-                               if (!strcmp (target_method->name, "get_Rank")) {
-                                       op = MINT_ARRAY_RANK;
-                               } else if (!strcmp (target_method->name, "get_Length")) {
-                                       op = MINT_LDLEN;
-                               } else if (!strcmp (target_method->name, "Address")) {
-                                       op = readonly ? MINT_LDELEMA : MINT_LDELEMA_TC;
-                               }
-                       } else if (target_method && generic_context) {
+
+                       if (generic_context) {
                                csignature = mono_inflate_generic_signature (csignature, generic_context, &error);
                                mono_error_cleanup (&error); /* FIXME: don't swallow the error */
                                target_method = mono_class_inflate_generic_method_checked (target_method, generic_context, &error);
@@ -722,6 +749,33 @@ interp_transform_call (TransformData *td, MonoMethod *method, MonoMethod *target
                csignature = mono_method_signature (target_method);
        }
 
+       /* Intrinsics */
+       if (target_method) {
+               if (target_method->klass == mono_defaults.string_class) {
+                       if (target_method->name [0] == 'g') {
+                               if (strcmp (target_method->name, "get_Chars") == 0)
+                                       op = MINT_GETCHR;
+                               else if (strcmp (target_method->name, "get_Length") == 0)
+                                       op = MINT_STRLEN;
+                       }
+               } else if (mono_class_is_subclass_of (target_method->klass, mono_defaults.array_class, FALSE)) {
+                       if (!strcmp (target_method->name, "get_Rank")) {
+                               op = MINT_ARRAY_RANK;
+                       } else if (!strcmp (target_method->name, "get_Length")) {
+                               op = MINT_LDLEN;
+                       } else if (!strcmp (target_method->name, "Address")) {
+                               op = readonly ? MINT_LDELEMA : MINT_LDELEMA_TC;
+                       }
+               } else if (target_method->klass->image == mono_defaults.corlib &&
+                                  (strcmp (target_method->klass->name_space, "System.Diagnostics") == 0) &&
+                                  (strcmp (target_method->klass->name, "Debugger") == 0)) {
+                       if (!strcmp (target_method->name, "Break") && csignature->param_count == 0) {
+                               if (mini_should_insert_breakpoint (method))
+                                       op = MINT_BREAK;
+                       }
+               }
+       }
+
        if (constrained_class) {
                if (constrained_class->enumtype && !strcmp (target_method->name, "GetHashCode")) {
                        /* Use the corresponding method from the base type to avoid boxing */
@@ -793,7 +847,7 @@ interp_transform_call (TransformData *td, MonoMethod *method, MonoMethod *target
                mono_class_init (target_method->klass);
 
        CHECK_STACK (td, csignature->param_count + csignature->hasthis);
-       if (!calli && (!virtual || (target_method->flags & METHOD_ATTRIBUTE_VIRTUAL) == 0) &&
+       if (!calli && op == -1 && (!virtual || (target_method->flags & METHOD_ATTRIBUTE_VIRTUAL) == 0) &&
                (target_method->flags & METHOD_ATTRIBUTE_PINVOKE_IMPL) == 0 && 
                (target_method->iflags & METHOD_IMPL_ATTRIBUTE_INTERNAL_CALL) == 0 &&
                !(target_method->iflags & METHOD_IMPL_ATTRIBUTE_NOINLINING)) {
@@ -802,7 +856,7 @@ interp_transform_call (TransformData *td, MonoMethod *method, MonoMethod *target
 
                if (/*mono_metadata_signature_equal (method->signature, target_method->signature) */ method == target_method && *(td->ip + 5) == CEE_RET) {
                        int offset;
-                       if (mono_interp_traceopt)
+                       if (td->verbose_level)
                                g_print ("Optimize tail call of %s.%s\n", target_method->klass->name, target_method->name);
 
                        for (i = csignature->param_count - 1 + !!csignature->hasthis; i >= 0; --i)
@@ -818,7 +872,7 @@ interp_transform_call (TransformData *td, MonoMethod *method, MonoMethod *target
                } else {
                        /* mheader might not exist if this is a delegate invoc, etc */
                        if (mheader && *mheader->code == CEE_RET && called_inited) {
-                               if (mono_interp_traceopt)
+                               if (td->verbose_level)
                                        g_print ("Inline (empty) call of %s.%s\n", target_method->klass->name, target_method->name);
                                for (i = 0; i < csignature->param_count; i++) {
                                        ADD_CODE (td, MINT_POP); /*FIX: vt */
@@ -926,6 +980,109 @@ interp_field_from_token (MonoMethod *method, guint32 token, MonoClass **klass, M
        return field;
 }
 
+static InterpBasicBlock*
+get_bb (TransformData *td, InterpBasicBlock *cbb, unsigned char *ip)
+{
+       int offset = ip - td->il_code;
+       InterpBasicBlock *bb = td->offset_to_bb [offset];
+
+       if (!bb) {
+               bb = mono_mempool_alloc0 (td->mempool, sizeof (InterpBasicBlock));
+               bb->ip = ip;
+               td->offset_to_bb [offset] = bb;
+
+               td->basic_blocks = g_list_append_mempool (td->mempool, td->basic_blocks, bb);
+       }
+
+       if (cbb)
+               bb->preds = g_slist_prepend_mempool (td->mempool, bb->preds, cbb);
+       return bb;
+}
+
+/*
+ * get_basic_blocks:
+ *
+ *   Compute the set of IL level basic blocks.
+ */
+static void
+get_basic_blocks (TransformData *td)
+{
+       guint8 *start = (guint8*)td->il_code;
+       guint8 *end = (guint8*)td->il_code + td->code_size;
+       guint8 *ip = start;
+       unsigned char *target;
+       int i;
+       guint cli_addr;
+       const MonoOpcode *opcode;
+       InterpBasicBlock *cbb;
+
+       td->offset_to_bb = mono_mempool_alloc0 (td->mempool, sizeof (InterpBasicBlock*) * (end - start + 1));
+       td->entry_bb = cbb = get_bb (td, NULL, start);
+
+       while (ip < end) {
+               cli_addr = ip - start;
+               td->offset_to_bb [cli_addr] = cbb;
+               i = mono_opcode_value ((const guint8 **)&ip, end);
+               opcode = &mono_opcodes [i];
+               switch (opcode->argument) {
+               case MonoInlineNone:
+                       ip++;
+                       break;
+               case MonoInlineString:
+               case MonoInlineType:
+               case MonoInlineField:
+               case MonoInlineMethod:
+               case MonoInlineTok:
+               case MonoInlineSig:
+               case MonoShortInlineR:
+               case MonoInlineI:
+                       ip += 5;
+                       break;
+               case MonoInlineVar:
+                       ip += 3;
+                       break;
+               case MonoShortInlineVar:
+               case MonoShortInlineI:
+                       ip += 2;
+                       break;
+               case MonoShortInlineBrTarget:
+                       target = start + cli_addr + 2 + (signed char)ip [1];
+                       get_bb (td, cbb, target);
+                       ip += 2;
+                       cbb = get_bb (td, cbb, ip);
+                       break;
+               case MonoInlineBrTarget:
+                       target = start + cli_addr + 5 + (gint32)read32 (ip + 1);
+                       get_bb (td, cbb, target);
+                       ip += 5;
+                       cbb = get_bb (td, cbb, ip);
+                       break;
+               case MonoInlineSwitch: {
+                       guint32 n = read32 (ip + 1);
+                       guint32 j;
+                       ip += 5;
+                       cli_addr += 5 + 4 * n;
+                       target = start + cli_addr;
+                       get_bb (td, cbb, target);
+
+                       for (j = 0; j < n; ++j) {
+                               target = start + cli_addr + (gint32)read32 (ip);
+                               get_bb (td, cbb, target);
+                               ip += 4;
+                       }
+                       cbb = get_bb (td, cbb, ip);
+                       break;
+               }
+               case MonoInlineR:
+               case MonoInlineI8:
+                       ip += 9;
+                       break;
+               default:
+                       g_assert_not_reached ();
+               }
+       }
+}
+
 static void
 interp_save_debug_info (RuntimeMethod *rtm, MonoMethodHeader *header, TransformData *td, GArray *line_numbers)
 {
@@ -940,14 +1097,26 @@ interp_save_debug_info (RuntimeMethod *rtm, MonoMethodHeader *header, TransformD
         */
 
        dinfo = g_new0 (MonoDebugMethodJitInfo, 1);
+       dinfo->num_params = rtm->param_count;
+       dinfo->params = g_new0 (MonoDebugVarInfo, dinfo->num_params);
        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->has_var_info = TRUE;
        dinfo->num_line_numbers = line_numbers->len;
        dinfo->line_numbers = g_new0 (MonoDebugLineNumberEntry, dinfo->num_line_numbers);
+
+       for (i = 0; i < dinfo->num_params; i++) {
+               MonoDebugVarInfo *var = &dinfo->params [i];
+               var->type = rtm->param_types [i];
+       }
+       for (i = 0; i < dinfo->num_locals; i++) {
+               MonoDebugVarInfo *var = &dinfo->locals [i];
+               var->type = header->locals [i];
+       }
+
        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 ());
@@ -955,6 +1124,201 @@ interp_save_debug_info (RuntimeMethod *rtm, MonoMethodHeader *header, TransformD
        mono_debug_free_method_jit_info (dinfo);
 }
 
+/* Same as the code in seq-points.c */
+static void
+insert_pred_seq_point (SeqPoint *last_sp, SeqPoint *sp, GSList **next)
+{
+       GSList *l;
+       int src_index = last_sp->next_offset;
+       int dst_index = sp->next_offset;
+
+       /* bb->in_bb might contain duplicates */
+       for (l = next [src_index]; l; l = l->next)
+               if (GPOINTER_TO_UINT (l->data) == dst_index)
+                       break;
+       if (!l)
+               next [src_index] = g_slist_append (next [src_index], GUINT_TO_POINTER (dst_index));
+}
+
+static void
+recursively_make_pred_seq_points (TransformData *td, InterpBasicBlock *bb)
+{
+       const gpointer MONO_SEQ_SEEN_LOOP = GINT_TO_POINTER(-1);
+       GSList *l;
+
+       GArray *predecessors = g_array_new (FALSE, TRUE, sizeof (gpointer));
+       GHashTable *seen = g_hash_table_new_full (g_direct_hash, NULL, NULL, NULL);
+
+       // Insert/remove sentinel into the memoize table to detect loops containing bb
+       bb->pred_seq_points = MONO_SEQ_SEEN_LOOP;
+
+       for (l = bb->preds; l; l = l->next) {
+               InterpBasicBlock *in_bb = l->data;
+
+               // This bb has the last seq point, append it and continue
+               if (in_bb->last_seq_point != NULL) {
+                       predecessors = g_array_append_val (predecessors, in_bb->last_seq_point);
+                       continue;
+               }
+
+               // We've looped or handled this before, exit early.
+               // No last sequence points to find.
+               if (in_bb->pred_seq_points == MONO_SEQ_SEEN_LOOP)
+                       continue;
+
+               // Take sequence points from incoming basic blocks
+
+               if (in_bb == td->entry_bb)
+                       continue;
+
+               if (in_bb->pred_seq_points == NULL)
+                       recursively_make_pred_seq_points (td, in_bb);
+
+               // Union sequence points with incoming bb's
+               for (int i=0; i < in_bb->num_pred_seq_points; i++) {
+                       if (!g_hash_table_lookup (seen, in_bb->pred_seq_points [i])) {
+                               g_array_append_val (predecessors, in_bb->pred_seq_points [i]);
+                               g_hash_table_insert (seen, in_bb->pred_seq_points [i], (gpointer)&MONO_SEQ_SEEN_LOOP);
+                       }
+               }
+               // predecessors = g_array_append_vals (predecessors, in_bb->pred_seq_points, in_bb->num_pred_seq_points);
+       }
+
+       g_hash_table_destroy (seen);
+
+       if (predecessors->len != 0) {
+               bb->pred_seq_points = mono_mempool_alloc0 (td->mempool, sizeof (SeqPoint *) * predecessors->len);
+               bb->num_pred_seq_points = predecessors->len;
+
+               for (int newer = 0; newer < bb->num_pred_seq_points; newer++) {
+                       bb->pred_seq_points [newer] = g_array_index (predecessors, gpointer, newer);
+               }
+       }
+
+       g_array_free (predecessors, TRUE);
+}
+
+static void
+collect_pred_seq_points (TransformData *td, InterpBasicBlock *bb, SeqPoint *seqp, GSList **next)
+{
+       // Doesn't have a last sequence point, must find from incoming basic blocks
+       if (bb->pred_seq_points == NULL && bb != td->entry_bb)
+               recursively_make_pred_seq_points (td, bb);
+
+       for (int i = 0; i < bb->num_pred_seq_points; i++)
+               insert_pred_seq_point (bb->pred_seq_points [i], seqp, next);
+
+       return;
+}
+
+static void
+save_seq_points (TransformData *td)
+{
+       RuntimeMethod *rtm = td->rtm;
+       GByteArray *array;
+       int i, seq_info_size;
+       MonoSeqPointInfo *info;
+       MonoDomain *domain = mono_domain_get ();
+       GSList **next = NULL;
+       GList *bblist;
+
+       if (!td->gen_sdb_seq_points)
+               return;
+
+       /*
+        * For each sequence point, compute the list of sequence points immediately
+        * following it, this is needed to implement 'step over' in the debugger agent.
+        * Similar to the code in mono_save_seq_point_info ().
+        */
+       for (i = 0; i < td->seq_points->len; ++i) {
+               SeqPoint *sp = g_ptr_array_index (td->seq_points, i);
+
+               /* Store the seq point index here temporarily */
+               sp->next_offset = i;
+       }
+       next = mono_mempool_alloc0 (td->mempool, sizeof (GList*) * td->seq_points->len);
+       for (bblist = td->basic_blocks; bblist; bblist = bblist->next) {
+               InterpBasicBlock *bb = bblist->data;
+
+               GSList *bb_seq_points = g_slist_reverse (bb->seq_points);
+               SeqPoint *last = NULL;
+               for (GSList *l = bb_seq_points; l; l = l->next) {
+                       SeqPoint *sp = l->data;
+
+                       if (sp->il_offset == METHOD_ENTRY_IL_OFFSET || sp->il_offset == METHOD_EXIT_IL_OFFSET)
+                               /* Used to implement method entry/exit events */
+                               continue;
+
+                       if (last != NULL) {
+                               /* Link with the previous seq point in the same bb */
+                               next [last->next_offset] = g_slist_append_mempool (td->mempool, next [last->next_offset], GINT_TO_POINTER (sp->next_offset));
+                       } else {
+                               /* Link with the last bb in the previous bblocks */
+                               collect_pred_seq_points (td, bb, sp, next);
+                       }
+                       last = sp;
+               }
+       }
+
+       /* Serialize the seq points into a byte array */
+       array = g_byte_array_new ();
+       SeqPoint zero_seq_point = {0};
+       SeqPoint* last_seq_point = &zero_seq_point;
+       for (i = 0; i < td->seq_points->len; ++i) {
+               SeqPoint *sp = (SeqPoint*)g_ptr_array_index (td->seq_points, i);
+
+               sp->next_offset = 0;
+               if (mono_seq_point_info_add_seq_point (array, sp, last_seq_point, next [i], TRUE))
+                       last_seq_point = sp;
+       }
+
+       if (td->verbose_level) {
+               g_print ("\nSEQ POINT MAP FOR %s: \n", td->method->name);
+
+               for (i = 0; i < td->seq_points->len; ++i) {
+                       SeqPoint *sp = (SeqPoint*)g_ptr_array_index (td->seq_points, i);
+                       GSList *l;
+
+                       if (!next [i])
+                               continue;
+
+                       g_print ("\tIL0x%x[0x%0x] ->", sp->il_offset, sp->native_offset);
+                       for (l = next [i]; l; l = l->next) {
+                               int next_index = GPOINTER_TO_UINT (l->data);
+                               g_print (" IL0x%x", ((SeqPoint*)g_ptr_array_index (td->seq_points, next_index))->il_offset);
+                       }
+                       g_print ("\n");
+               }
+       }
+
+       info = mono_seq_point_info_new (array->len, TRUE, array->data, TRUE, &seq_info_size);
+       mono_jit_stats.allocated_seq_points_size += seq_info_size;
+
+       g_byte_array_free (array, TRUE);
+
+       mono_domain_lock (domain);
+       g_hash_table_insert (domain_jit_info (domain)->seq_points, rtm->method, info);
+       mono_domain_unlock (domain);
+}
+
+static void
+emit_seq_point (TransformData *td, int il_offset, InterpBasicBlock *cbb, gboolean nonempty_stack)
+{
+       SeqPoint *seqp;
+
+       seqp = mono_mempool_alloc0 (td->mempool, sizeof (SeqPoint));
+       seqp->il_offset = il_offset;
+       seqp->native_offset = (guint8*)td->new_ip - (guint8*)td->new_code;
+       if (nonempty_stack)
+               seqp->flags |= MONO_SEQ_POINT_FLAG_NONEMPTY_STACK;
+
+       ADD_CODE (td, MINT_SDB_SEQ_POINT);
+       g_ptr_array_add (td->seq_points, seqp);
+
+       cbb->seq_points = g_slist_prepend_mempool (td->mempool, cbb->seq_points, seqp);
+       cbb->last_seq_point = seqp;
+}
+
 static void
 generate (MonoMethod *method, RuntimeMethod *rtm, unsigned char *is_bb_start, MonoGenericContext *generic_context)
 {
@@ -976,8 +1340,20 @@ generate (MonoMethod *method, RuntimeMethod *rtm, unsigned char *is_bb_start, Mo
        TransformData td;
        int generating_code = 1;
        GArray *line_numbers;
+       MonoDebugMethodInfo *minfo;
+       MonoBitSet *seq_point_locs = NULL;
+       MonoBitSet *seq_point_set_locs = NULL;
+       gboolean sym_seq_points = FALSE;
+       InterpBasicBlock *bb_exit = NULL;
+       static gboolean verbose_method_inited;
+       static char* verbose_method_name;
+
+       if (!verbose_method_inited) {
+               verbose_method_name = getenv ("MONO_VERBOSE_METHOD");
+               verbose_method_inited = TRUE;
+       }
 
-       memset(&td, 0, sizeof(td));
+       memset (&td, 0, sizeof(td));
        td.method = method;
        td.rtm = rtm;
        td.is_bb_start = is_bb_start;
@@ -987,8 +1363,8 @@ generate (MonoMethod *method, RuntimeMethod *rtm, unsigned char *is_bb_start, Mo
        td.max_code_size = td.code_size;
        td.new_code = (unsigned short *)g_malloc(td.max_code_size * sizeof(gushort));
        td.new_code_end = td.new_code + td.max_code_size;
+       td.mempool = mono_mempool_new ();
        td.in_offsets = g_malloc0(header->code_size * sizeof(int));
-       td.forward_refs = g_malloc(header->code_size * sizeof(int));
        td.stack_state = g_malloc0(header->code_size * sizeof(StackInfo *));
        td.stack_height = g_malloc(header->code_size * sizeof(int));
        td.vt_stack_size = g_malloc(header->code_size * sizeof(int));
@@ -997,12 +1373,61 @@ generate (MonoMethod *method, RuntimeMethod *rtm, unsigned char *is_bb_start, Mo
        td.data_items = NULL;
        td.data_hash = g_hash_table_new (NULL, NULL);
        td.clause_indexes = g_malloc (header->code_size * sizeof (int));
+       td.gen_sdb_seq_points = debug_options.gen_sdb_seq_points;
+       td.seq_points = g_ptr_array_new ();
+       td.relocs = g_ptr_array_new ();
+       td.verbose_level = mono_interp_traceopt;
        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;
        }
+
+       if (verbose_method_name) {
+               const char *name = verbose_method_name;
+
+               if ((strchr (name, '.') > name) || strchr (name, ':')) {
+                       MonoMethodDesc *desc;
+
+                       desc = mono_method_desc_new (name, TRUE);
+                       if (mono_method_desc_full_match (desc, method)) {
+                               td.verbose_level = 4;
+                       }
+                       mono_method_desc_free (desc);
+               } else {
+                       if (strcmp (method->name, name) == 0)
+                               td.verbose_level = 4;
+               }
+       }
+
+       if (td.gen_sdb_seq_points) {
+               get_basic_blocks (&td);
+
+               minfo = mono_debug_lookup_method (method);
+
+               if (minfo) {
+                       MonoSymSeqPoint *sps;
+                       int i, n_il_offsets;
+
+                       mono_debug_get_seq_points (minfo, NULL, NULL, NULL, &sps, &n_il_offsets);
+                       // FIXME: Free
+                       seq_point_locs = mono_bitset_mem_new (mono_mempool_alloc0 (td.mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
+                       seq_point_set_locs = mono_bitset_mem_new (mono_mempool_alloc0 (td.mempool, mono_bitset_alloc_size (header->code_size, 0)), header->code_size, 0);
+                       sym_seq_points = TRUE;
+
+                       for (i = 0; i < n_il_offsets; ++i) {
+                               if (sps [i].il_offset < header->code_size)
+                                       mono_bitset_set_fast (seq_point_locs, sps [i].il_offset);
+                       }
+                       g_free (sps);
+               } else if (!method->wrapper_type && !method->dynamic && mono_debug_image_has_debug_info (method->klass->image)) {
+                       /* Methods without line number info like auto-generated property accessors */
+                       seq_point_locs = mono_bitset_new (header->code_size, 0);
+                       seq_point_set_locs = mono_bitset_new (header->code_size, 0);
+                       sym_seq_points = TRUE;
+               }
+       }
+
        td.new_ip = td.new_code;
        td.last_new_ip = NULL;
 
@@ -1045,7 +1470,7 @@ generate (MonoMethod *method, RuntimeMethod *rtm, unsigned char *is_bb_start, Mo
        td.ip = header->code;
        end = td.ip + header->code_size;
 
-       if (mono_interp_traceopt) {
+       if (td.verbose_level) {
                char *tmp = mono_disasm_code (NULL, method, td.ip, end);
                char *name = mono_method_full_name (method, TRUE);
                g_print ("Method %s, original code:\n", name);
@@ -1069,6 +1494,12 @@ generate (MonoMethod *method, RuntimeMethod *rtm, unsigned char *is_bb_start, Mo
                }
        }
 
+       if (sym_seq_points) {
+               InterpBasicBlock *cbb = td.offset_to_bb [0];
+               g_assert (cbb);
+               emit_seq_point (&td, METHOD_ENTRY_IL_OFFSET, cbb, FALSE);
+       }
+
        while (td.ip < end) {
                int in_offset;
 
@@ -1080,38 +1511,10 @@ generate (MonoMethod *method, RuntimeMethod *rtm, unsigned char *is_bb_start, Mo
                td.in_start = td.ip;
 
                MonoDebugLineNumberEntry lne;
-               lne.native_offset = td.new_ip - td.new_code;
-               lne.il_offset = td.ip - header->code;
+               lne.native_offset = (guint8*)td.new_ip - (guint8*)td.new_code;
+               lne.il_offset = in_offset;
                g_array_append_val (line_numbers, lne);
 
-               while (td.forward_refs [in_offset] >= 0) {
-                       int j = td.forward_refs [in_offset];
-                       int slot;
-                       td.forward_refs [in_offset] = td.forward_refs [j];
-                       if (td.in_offsets [j] < 0) {                        
-                               int old_switch_offset = -td.in_offsets [j];
-                               int new_switch_offset = td.in_offsets [old_switch_offset];
-                               int switch_case = (j - old_switch_offset - 5) / 4;
-                               int n_cases = read32 (header->code + old_switch_offset + 1);
-                               offset = (td.new_ip - td.new_code) - (new_switch_offset + 2 * n_cases + 3);
-                               slot = new_switch_offset + 3 + 2 * switch_case;
-                               td.new_code [slot] = * (unsigned short *)(&offset);
-                               td.new_code [slot + 1] = * ((unsigned short *)&offset + 1);
-                       } else {
-                               int op = td.new_code [td.in_offsets [j]];
-                               if (mono_interp_opargtype [op] == MintOpShortBranch) {
-                                       offset = (td.new_ip - td.new_code) - td.in_offsets [j];
-                                       g_assert (offset <= 32767);
-                                       slot = td.in_offsets [j] + 1;
-                                       td.new_code [slot] = offset;
-                               } else {
-                                       offset = (td.new_ip - td.new_code) - td.in_offsets [j];
-                                       slot = td.in_offsets [j] + 1;
-                                       td.new_code [slot] = * (unsigned short *)(&offset);
-                                       td.new_code [slot + 1] = * ((unsigned short *)&offset + 1);
-                               }
-                       }
-               }
                if (td.stack_height [in_offset] >= 0) {
                        g_assert (is_bb_start [in_offset]);
                        if (td.stack_height [in_offset] > 0)
@@ -1127,7 +1530,7 @@ generate (MonoMethod *method, RuntimeMethod *rtm, unsigned char *is_bb_start, Mo
                                ++td.ip;
                        continue;
                }
-               if (mono_interp_traceopt > 1) {
+               if (td.verbose_level > 1) {
                        printf("IL_%04lx %s %-10s -> IL_%04lx, sp %ld, %s %-12s vt_sp %u (max %u)\n", 
                                td.ip - td.il_code,
                                td.is_bb_start [td.ip - td.il_code] == 3 ? "<>" :
@@ -1138,6 +1541,26 @@ generate (MonoMethod *method, RuntimeMethod *rtm, unsigned char *is_bb_start, Mo
                                (td.sp > td.stack && (td.sp [-1].type == STACK_TYPE_O || td.sp [-1].type == STACK_TYPE_VT)) ? (td.sp [-1].klass == NULL ? "?" : td.sp [-1].klass->name) : "",
                                td.vt_sp, td.max_vt_sp);
                }
+
+               if (sym_seq_points && mono_bitset_test_fast (seq_point_locs, td.ip - header->code)) {
+                       InterpBasicBlock *cbb = td.offset_to_bb [td.ip - header->code];
+                       g_assert (cbb);
+
+                       /*
+                        * Make methods interruptable at the beginning, and at the targets of
+                        * backward branches.
+                        */
+                       if (in_offset == 0 || g_slist_length (cbb->preds) > 1)
+                               ADD_CODE (&td, MINT_SDB_INTR_LOC);
+
+                       emit_seq_point (&td, in_offset, cbb, FALSE);
+
+                       mono_bitset_set_fast (seq_point_set_locs, td.ip - header->code);
+               }
+
+               if (sym_seq_points)
+                       bb_exit = td.offset_to_bb [td.ip - header->code];
+
                switch (*td.ip) {
                case CEE_NOP: 
                        /* lose it */
@@ -1318,7 +1741,20 @@ generate (MonoMethod *method, RuntimeMethod *rtm, unsigned char *is_bb_start, Mo
                case CEE_CALLVIRT: /* Fall through */
                case CEE_CALLI:    /* Fall through */
                case CEE_CALL: {
+                       gboolean need_seq_point = FALSE;
+
+                       if (sym_seq_points && !mono_bitset_test_fast (seq_point_locs, td.ip + 5 - header->code))
+                               need_seq_point = TRUE;
+
                        interp_transform_call (&td, method, NULL, domain, generic_context, is_bb_start, body_start_offset, constrained_class, readonly);
+
+                       if (need_seq_point) {
+                               InterpBasicBlock *cbb = td.offset_to_bb [td.ip - header->code];
+                               g_assert (cbb);
+
+                               emit_seq_point (&td, td.ip - header->code, cbb, TRUE);
+                       }
+
                        constrained_class = NULL;
                        readonly = FALSE;
                        break;
@@ -1337,6 +1773,13 @@ generate (MonoMethod *method, RuntimeMethod *rtm, unsigned char *is_bb_start, Mo
                                g_warning ("%s.%s: CEE_RET: more values on stack: %d", td.method->klass->name, td.method->name, td.sp - td.stack);
                        if (td.vt_sp != vt_size)
                                g_error ("%s.%s: CEE_RET: value type stack: %d vs. %d", td.method->klass->name, td.method->name, td.vt_sp, vt_size);
+
+                       if (sym_seq_points) {
+                               InterpBasicBlock *cbb = td.offset_to_bb [td.ip - header->code];
+                               g_assert (cbb);
+                               emit_seq_point (&td, METHOD_EXIT_IL_OFFSET, bb_exit, FALSE);
+                       }
+
                        if (vt_size == 0)
                                SIMPLE_OP(td, signature->ret->type == MONO_TYPE_VOID ? MINT_RET_VOID : MINT_RET);
                        else {
@@ -1456,15 +1899,12 @@ generate (MonoMethod *method, RuntimeMethod *rtm, unsigned char *is_bb_start, Mo
                case CEE_SWITCH: {
                        guint32 n;
                        const unsigned char *next_ip;
-                       const unsigned char *base_ip = td.ip;
-                       unsigned short *next_new_ip;
                        ++td.ip;
                        n = read32 (td.ip);
                        ADD_CODE (&td, MINT_SWITCH);
                        WRITE32 (&td, &n);
                        td.ip += 4;
                        next_ip = td.ip + n * 4;
-                       next_new_ip = td.new_ip + n * 2;
                        --td.sp;
                        int stack_height = td.sp - td.stack;
                        for (i = 0; i < n; i++) {
@@ -1475,16 +1915,19 @@ generate (MonoMethod *method, RuntimeMethod *rtm, unsigned char *is_bb_start, Mo
                                        if (stack_height > 0 && stack_height != td.stack_height [target])
                                                g_warning ("SWITCH with back branch and non-empty stack");
 #endif
-                                       target = td.in_offsets [target] - (next_new_ip - td.new_code);
+                                       target = td.in_offsets [target] - (td.new_ip - td.new_code);
                                } else {
                                        td.stack_height [target] = stack_height;
                                        td.vt_stack_size [target] = td.vt_sp;
                                        if (stack_height > 0)
                                                td.stack_state [target] = g_memdup (td.stack, stack_height * sizeof (td.stack [0]));
-                                       int prev = td.forward_refs [target];
-                                       td.forward_refs [td.ip - td.il_code] = prev;
-                                       td.forward_refs [target] = td.ip - td.il_code;
-                                       td.in_offsets [td.ip - td.il_code] = - (base_ip - td.il_code);
+
+                                       Reloc *reloc = mono_mempool_alloc0 (td.mempool, sizeof (Reloc));
+                                       reloc->type = RELOC_SWITCH;
+                                       reloc->offset = td.new_ip - td.new_code;
+                                       reloc->target = target;
+                                       g_ptr_array_add (td.relocs, reloc);
+                                       target = 0xffff;
                                }
                                WRITE32 (&td, &target);
                                td.ip += 4;
@@ -1942,12 +2385,13 @@ generate (MonoMethod *method, RuntimeMethod *rtm, unsigned char *is_bb_start, Mo
                        MonoString *s;
                        token = mono_metadata_token_index (read32 (td.ip + 1));
                        td.ip += 5;
-                       if (method->wrapper_type != MONO_WRAPPER_NONE) {
-                               s = mono_string_new_wrapper(
-                                       mono_method_get_wrapper_data (method, token));
-                       }
-                       else
+                       if (method->wrapper_type == MONO_WRAPPER_DYNAMIC_METHOD) {
+                               s = mono_method_get_wrapper_data (method, token);
+                       } else if (method->wrapper_type != MONO_WRAPPER_NONE) {
+                               s = mono_string_new_wrapper (mono_method_get_wrapper_data (method, token));
+                       } else {
                                s = mono_ldstr (domain, image, token);
+                       }
                        ADD_CODE(&td, MINT_LDSTR);
                        ADD_CODE(&td, get_data_item_index (&td, s));
                        PUSH_TYPE(&td, STACK_TYPE_O, mono_defaults.string_class);
@@ -3341,9 +3785,35 @@ generate (MonoMethod *method, RuntimeMethod *rtm, unsigned char *is_bb_start, Mo
                td.last_ip = td.in_start;
        }
 
-       if (mono_interp_traceopt) {
+       /* Handle relocations */
+       for (int i = 0; i < td.relocs->len; ++i) {
+               Reloc *reloc = g_ptr_array_index (td.relocs, i);
+
+               int offset = td.in_offsets [reloc->target] - reloc->offset;
+
+               switch (reloc->type) {
+               case RELOC_SHORT_BRANCH:
+                       g_assert (td.new_code [reloc->offset + 1] == 0xffff);
+                       td.new_code [reloc->offset + 1] = offset;
+                       break;
+               case RELOC_LONG_BRANCH:
+                       g_assert_not_reached ();
+                       break;
+               case RELOC_SWITCH: {
+                       guint16 *v = (guint16*)&offset;
+                       td.new_code [reloc->offset] = *(guint16*)v;
+                       td.new_code [reloc->offset + 1] = *(guint16*)(v + 1);
+                       break;
+               }
+               default:
+                       g_assert_not_reached ();
+                       break;
+               }
+       }
+
+       if (td.verbose_level) {
                const guint16 *p = td.new_code;
-               printf("Runtime method: %p, VT stack size: %d\n", rtm, td.max_vt_sp);
+               printf("Runtime method: %s %p, VT stack size: %d\n", mono_method_full_name (method, TRUE), rtm, td.max_vt_sp);
                printf("Calculated stack size: %d, stated size: %d\n", td.max_stack_height, header->max_stack);
                while (p < td.new_ip) {
                        p = mono_interp_dis_mintop(td.new_code, p);
@@ -3383,6 +3853,7 @@ generate (MonoMethod *method, RuntimeMethod *rtm, unsigned char *is_bb_start, Mo
        /* 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);
+       jinfo->is_interp = 1;
        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) {
@@ -3390,17 +3861,18 @@ generate (MonoMethod *method, RuntimeMethod *rtm, unsigned char *is_bb_start, Mo
                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;
+               ei->try_start = (guint8*)(rtm->code + c->try_offset);
+               ei->try_end = (guint8*)(rtm->code + c->try_offset + c->try_len);
+               ei->handler_start = (guint8*)(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;
                }
        }
 
+       save_seq_points (&td);
+
        g_free (td.in_offsets);
-       g_free (td.forward_refs);
        for (i = 0; i < header->code_size; ++i)
                g_free (td.stack_state [i]);
        g_free (td.stack_state);
@@ -3410,7 +3882,10 @@ generate (MonoMethod *method, RuntimeMethod *rtm, unsigned char *is_bb_start, Mo
        g_free (td.stack);
        g_hash_table_destroy (td.data_hash);
        g_free (td.clause_indexes);
+       g_ptr_array_free (td.seq_points, TRUE);
        g_array_free (line_numbers, TRUE);
+       g_ptr_array_free (td.relocs, TRUE);
+       mono_mempool_destroy (td.mempool);
 }
 
 static mono_mutex_t calc_section;
@@ -3481,7 +3956,7 @@ mono_interp_transform_method (RuntimeMethod *runtime_method, ThreadContext *cont
                mono_os_mutex_lock(&calc_section);
                if (runtime_method->transformed) {
                        mono_os_mutex_unlock(&calc_section);
-                       mono_profiler_method_end_jit (method, NULL, MONO_PROFILE_OK);
+                       mono_profiler_method_end_jit (method, runtime_method->jinfo, MONO_PROFILE_OK);
                        return NULL;
                }
 
@@ -3656,7 +4131,7 @@ mono_interp_transform_method (RuntimeMethod *runtime_method, ThreadContext *cont
        if (runtime_method->transformed) {
                mono_os_mutex_unlock(&calc_section);
                g_free (is_bb_start);
-               mono_profiler_method_end_jit (method, NULL, MONO_PROFILE_OK);
+               mono_profiler_method_end_jit (method, runtime_method->jinfo, MONO_PROFILE_OK);
                return NULL;
        }
 
@@ -3707,7 +4182,8 @@ mono_interp_transform_method (RuntimeMethod *runtime_method, ThreadContext *cont
 
        g_free (is_bb_start);
 
-       mono_profiler_method_end_jit (method, NULL, MONO_PROFILE_OK);
+       // FIXME: Add a different callback ?
+       mono_profiler_method_end_jit (method, runtime_method->jinfo, MONO_PROFILE_OK);
        runtime_method->transformed = TRUE;
        mono_os_mutex_unlock(&calc_section);
 
index 5ce249f7f43d86e8a9ef71088b08702322186729..78be8ee709af0aaf5317f5ff1b46daa91481a430 100644 (file)
@@ -4571,54 +4571,6 @@ mini_emit_ldelema_ins (MonoCompile *cfg, MonoMethod *cmethod, MonoInst **sp, uns
        return addr;
 }
 
-static MonoBreakPolicy
-always_insert_breakpoint (MonoMethod *method)
-{
-       return MONO_BREAK_POLICY_ALWAYS;
-}
-
-static MonoBreakPolicyFunc break_policy_func = always_insert_breakpoint;
-
-/**
- * mono_set_break_policy:
- * \param policy_callback the new callback function
- *
- * Allow embedders to decide wherther to actually obey breakpoint instructions
- * (both break IL instructions and \c Debugger.Break method calls), for example
- * to not allow an app to be aborted by a perfectly valid IL opcode when executing
- * untrusted or semi-trusted code.
- *
- * \p policy_callback will be called every time a break point instruction needs to
- * be inserted with the method argument being the method that calls \c Debugger.Break
- * or has the IL \c break instruction. The callback should return \c MONO_BREAK_POLICY_NEVER
- * if it wants the breakpoint to not be effective in the given method.
- * \c MONO_BREAK_POLICY_ALWAYS is the default.
- */
-void
-mono_set_break_policy (MonoBreakPolicyFunc policy_callback)
-{
-       if (policy_callback)
-               break_policy_func = policy_callback;
-       else
-               break_policy_func = always_insert_breakpoint;
-}
-
-static gboolean
-should_insert_brekpoint (MonoMethod *method) {
-       switch (break_policy_func (method)) {
-       case MONO_BREAK_POLICY_ALWAYS:
-               return TRUE;
-       case MONO_BREAK_POLICY_NEVER:
-               return FALSE;
-       case MONO_BREAK_POLICY_ON_DBG:
-               g_warning ("mdb no longer supported");
-               return FALSE;
-       default:
-               g_warning ("Incorrect value returned from break policy callback");
-               return FALSE;
-       }
-}
-
 /* optimize the simple GetGenericValueImpl/SetGenericValueImpl generic icalls */
 static MonoInst*
 emit_array_generic_access (MonoCompile *cfg, MonoMethodSignature *fsig, MonoInst **args, int is_set)
@@ -5738,7 +5690,7 @@ mini_emit_inst_for_method (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSign
                           (strcmp (cmethod->klass->name_space, "System.Diagnostics") == 0) &&
                           (strcmp (cmethod->klass->name, "Debugger") == 0)) {
                if (!strcmp (cmethod->name, "Break") && fsig->param_count == 0) {
-                       if (should_insert_brekpoint (cfg->method)) {
+                       if (mini_should_insert_breakpoint (cfg->method)) {
                                ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
                        } else {
                                MONO_INST_NEW (cfg, ins, OP_NOP);
@@ -7766,7 +7718,7 @@ mono_method_to_ir (MonoCompile *cfg, MonoMethod *method, MonoBasicBlock *start_b
                        MONO_ADD_INS (cfg->cbb, ins);
                        break;
                case CEE_BREAK:
-                       if (should_insert_brekpoint (cfg->method)) {
+                       if (mini_should_insert_breakpoint (cfg->method)) {
                                ins = mono_emit_jit_icall (cfg, mono_debugger_agent_user_break, NULL);
                        } else {
                                MONO_INST_NEW (cfg, ins, OP_NOP);
@@ -14196,11 +14148,4 @@ NOTES
   the values on the stack before emitting the last instruction of the bb.
 */
 
-#else /* !DISABLE_JIT */
-
-void
-mono_set_break_policy (MonoBreakPolicyFunc policy_callback)
-{
-}
-
 #endif /* !DISABLE_JIT */
index b6b1d813399f21e758c9ff90188d8b3f9ddf139e..7878372c10cd57257517b52809e147cb42c654bf 100644 (file)
@@ -1070,6 +1070,7 @@ mono_walk_stack_full (MonoJitStackWalk func, MonoContext *start_ctx, MonoDomain
        mgreg_t *new_reg_locations [MONO_MAX_IREGS];
        gboolean get_reg_locations = unwind_options & MONO_UNWIND_REG_LOCATIONS;
        gboolean async = mono_thread_info_is_async_context ();
+       Unwinder unwinder;
 
        if (mono_llvm_only) {
                GSList *l, *ips;
@@ -1114,9 +1115,11 @@ mono_walk_stack_full (MonoJitStackWalk func, MonoContext *start_ctx, MonoDomain
        memcpy (&ctx, start_ctx, sizeof (MonoContext));
        memset (reg_locations, 0, sizeof (reg_locations));
 
+       unwinder_init (&unwinder);
+
        while (MONO_CONTEXT_GET_SP (&ctx) < jit_tls->end_of_stack) {
                frame.lmf = lmf;
-               res = mono_find_jit_info_ext (domain, jit_tls, NULL, &ctx, &new_ctx, NULL, &lmf, get_reg_locations ? new_reg_locations : NULL, &frame);
+               res = unwinder_unwind_frame (&unwinder, domain, jit_tls, NULL, &ctx, &new_ctx, NULL, &lmf, get_reg_locations ? new_reg_locations : NULL, &frame);
                if (!res)
                        return;
 
@@ -1633,7 +1636,7 @@ mono_handle_exception_internal_first_pass (MonoContext *ctx, MonoObject *obj, gi
 
                gpointer ip;
                if (in_interp)
-                       ip = (guint16*)ji->code_start + frame.native_offset;
+                       ip = (guint8*)ji->code_start + frame.native_offset;
                else
                        ip = MONO_CONTEXT_GET_IP (ctx);
 
@@ -2009,7 +2012,7 @@ mono_handle_exception_internal (MonoContext *ctx, MonoObject *obj, gboolean resu
                }
 
                if (in_interp)
-                       ip = (guint16*)ji->code_start + frame.native_offset;
+                       ip = (guint8*)ji->code_start + frame.native_offset;
                else
                        ip = MONO_CONTEXT_GET_IP (ctx);
 
@@ -2131,7 +2134,7 @@ mono_handle_exception_internal (MonoContext *ctx, MonoObject *obj, gboolean resu
                                                 * 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);
+                                               mono_interp_set_resume_state (jit_tls, mono_ex, frame.interp_frame, ei->handler_start);
                                                /* Undo the IP adjustment done by mono_arch_unwind_frame () */
 #if defined(TARGET_AMD64)
                                                ctx->gregs [AMD64_RIP] ++;
@@ -2260,6 +2263,9 @@ mono_debugger_run_finally (MonoContext *start_ctx)
  * mono_handle_exception:
  * \param ctx saved processor state
  * \param obj the exception object
+ *
+ *   Handle the exception OBJ starting from the state CTX. Modify CTX to point to the handler clause if the exception is caught, and
+ * return TRUE.
  */
 gboolean
 mono_handle_exception (MonoContext *ctx, MonoObject *obj)
@@ -3407,31 +3413,3 @@ 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
index 33b95a61779826af5dcdb7759200be9c4a261a63..7d427a915ee53263ccff6c19689782a15c5c48d7 100644 (file)
@@ -4547,6 +4547,56 @@ mono_personality (void)
        g_assert_not_reached ();
 }
 
+
+static MonoBreakPolicy
+always_insert_breakpoint (MonoMethod *method)
+{
+       return MONO_BREAK_POLICY_ALWAYS;
+}
+
+static MonoBreakPolicyFunc break_policy_func = always_insert_breakpoint;
+
+/**
+ * mono_set_break_policy:
+ * \param policy_callback the new callback function
+ *
+ * Allow embedders to decide whether to actually obey breakpoint instructions
+ * (both break IL instructions and \c Debugger.Break method calls), for example
+ * to not allow an app to be aborted by a perfectly valid IL opcode when executing
+ * untrusted or semi-trusted code.
+ *
+ * \p policy_callback will be called every time a break point instruction needs to
+ * be inserted with the method argument being the method that calls \c Debugger.Break
+ * or has the IL \c break instruction. The callback should return \c MONO_BREAK_POLICY_NEVER
+ * if it wants the breakpoint to not be effective in the given method.
+ * \c MONO_BREAK_POLICY_ALWAYS is the default.
+ */
+void
+mono_set_break_policy (MonoBreakPolicyFunc policy_callback)
+{
+       if (policy_callback)
+               break_policy_func = policy_callback;
+       else
+               break_policy_func = always_insert_breakpoint;
+}
+
+gboolean
+mini_should_insert_breakpoint (MonoMethod *method)
+{
+       switch (break_policy_func (method)) {
+       case MONO_BREAK_POLICY_ALWAYS:
+               return TRUE;
+       case MONO_BREAK_POLICY_NEVER:
+               return FALSE;
+       case MONO_BREAK_POLICY_ON_DBG:
+               g_warning ("mdb no longer supported");
+               return FALSE;
+       default:
+               g_warning ("Incorrect value returned from break policy callback");
+               return FALSE;
+       }
+}
+
 // Custom handlers currently only implemented by Windows.
 #ifndef HOST_WIN32
 gboolean
index c9a18e873622329602f8b2d26a54817fe8a52d91..ed10d8f937934da36d172b9a60b1b2847947453d 100644 (file)
@@ -1217,11 +1217,12 @@ typedef struct {
         */
        gpointer abort_exc_stack_threshold;
 
-
        /*
         * List of methods being JIT'd in the current thread.
         */
        int active_jit_methods;
+
+       gpointer interp_context;
 } MonoJitTlsData;
 
 /*
@@ -2481,6 +2482,7 @@ MonoInst* mono_emit_jit_icall_by_info (MonoCompile *cfg, int il_offset, MonoJitI
 MonoInst* mono_emit_method_call (MonoCompile *cfg, MonoMethod *method, MonoInst **args, MonoInst *this_ins);
 void      mono_create_helper_signatures (void);
 MonoInst* mono_emit_native_call (MonoCompile *cfg, gconstpointer func, MonoMethodSignature *sig, MonoInst **args);
+gboolean  mini_should_insert_breakpoint (MonoMethod *method);
 
 gboolean  mini_class_is_system_array (MonoClass *klass);
 MonoMethodSignature *mono_get_element_address_signature (int arity);
index f5449aa086c20d8e6a2b95bcd9a3c28021cba134..70dc4b0554c6eb8d780d1a2c8dcd7feb348ab91a 100644 (file)
     <ClCompile Include="..\mono\mini\mini-native-types.c" />\r
     <ClCompile Include="..\mono\mini\type-checking.c" />\r
     <ClCompile Include="..\mono\mini\lldb.c" />\r
+    <ClCompile Include="..\mono\mini\interp\interp-stubs.c" />\r
   </ItemGroup>\r
   <PropertyGroup Label="Globals">\r
     <ProjectGuid>{CB0D9E92-293C-439C-9AC7-C5F59B6E0772}</ProjectGuid>\r
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />\r
   <ImportGroup Label="ExtensionTargets">\r
   </ImportGroup>\r
-</Project>
\ No newline at end of file
+</Project>\r
index 3ff2406521426133728ed01ee90cfdaa43931fda..029b9d162c15144f2740162e2726bb56fb2572ac 100644 (file)
     <ClCompile Include="..\mono\mini\lldb.c">\r
       <Filter>Source Files</Filter>\r
     </ClCompile>\r
+    <ClCompile Include="..\mono\mini\interp\interp-stubs.c">\r
+      <Filter>Source Files</Filter>\r
+    </ClCompile>\r
   </ItemGroup>\r
   <ItemGroup>\r
     <ClInclude Include="..\mono\mini\abcremoval.h">\r
       <Filter>Resource Files</Filter>\r
     </None>\r
   </ItemGroup>\r
-</Project>
\ No newline at end of file
+</Project>\r