2009-12-21 Zoltan Varga <vargaz@gmail.com>
authorZoltan Varga <vargaz@gmail.com>
Mon, 21 Dec 2009 21:33:17 +0000 (21:33 -0000)
committerZoltan Varga <vargaz@gmail.com>
Mon, 21 Dec 2009 21:33:17 +0000 (21:33 -0000)
* mini.c (mono_add_seq_point): New helper function.
(mono_save_seq_point_info): New function to save sequence point info, extracted
from mini_method_compile ().

* mini-<ARCH>.c: Call mono_add_seq_point to remember sequence points.

* mini.h (MonoSeqPointInfo): New structure containing information about
the sequence points of a JITted method.
(MonoBasicBlock): Add 'seq_points' and 'last_seq_point' fields. Remove unused
'bucket' field.

* mini.c debugger-agent.c aot-compiler.c aot-runtime.c: Change the way sequence
point information is stored, use a MonoSeqPointInfo structure instead of a
GPtrArray. For each seq point, compute a list of successor seq points.

* debugger-agent.c: Use the successor list to implement step-over more
efficiently: instead of single stepping until a different line/IL offset is
reached, place breakpoints into all successor seq points.

* mini.h: Bump AOT file format version.

svn path=/trunk/mono/; revision=148820

mono/mini/ChangeLog
mono/mini/aot-compiler.c
mono/mini/aot-runtime.c
mono/mini/debugger-agent.c
mono/mini/mini-amd64.c
mono/mini/mini-arm.c
mono/mini/mini-ppc.c
mono/mini/mini-x86.c
mono/mini/mini.c
mono/mini/mini.h

index 70b803aa27ff5bc6c9b4cf8ec3638c287d25789a..3595bef9552bfdc9fb818af5b92cb78c2910b74f 100644 (file)
@@ -1,3 +1,26 @@
+2009-12-21  Zoltan Varga  <vargaz@gmail.com>
+
+       * mini.c (mono_add_seq_point): New helper function.
+       (mono_save_seq_point_info): New function to save sequence point info, extracted
+       from mini_method_compile ().
+
+       * mini-<ARCH>.c: Call mono_add_seq_point to remember sequence points.
+
+       * mini.h (MonoSeqPointInfo): New structure containing information about
+       the sequence points of a JITted method.
+       (MonoBasicBlock): Add 'seq_points' and 'last_seq_point' fields. Remove unused
+       'bucket' field.
+
+       * mini.c debugger-agent.c aot-compiler.c aot-runtime.c: Change the way sequence
+       point information is stored, use a MonoSeqPointInfo structure instead of a
+       GPtrArray. For each seq point, compute a list of successor seq points.
+
+       * debugger-agent.c: Use the successor list to implement step-over more
+       efficiently: instead of single stepping until a different line/IL offset is
+       reached, place breakpoints into all successor seq points.
+
+       * mini.h: Bump AOT file format version.
+
 2009-12-21  Zoltan Varga  <vargaz@gmail.com>
 
        * Makefile.am (AM_CFLAGS): Include LLVM_CFLAGS.
index e8bdd1432b17bc0f43f1ac995bd9f2335a8ab783..08ffe000a634275aa9b0f561a1e24aec6f61fdd9 100644 (file)
@@ -3085,7 +3085,7 @@ emit_exception_debug_info (MonoAotCompile *acfg, MonoCompile *cfg)
        MonoJitInfo *jinfo = cfg->jit_info;
        guint32 flags;
        gboolean use_unwind_ops = FALSE;
-       GPtrArray *seq_points;
+       MonoSeqPointInfo *seq_points;
 
        method = cfg->orig_method;
        code = cfg->native_code;
@@ -3100,15 +3100,15 @@ emit_exception_debug_info (MonoAotCompile *acfg, MonoCompile *cfg)
                debug_info_size = 0;
        }
 
-       buf_size = header->num_clauses * 256 + debug_info_size + 1024 + (cfg->seq_points ? (cfg->seq_points->len * 16) : 0);
+       seq_points = cfg->seq_point_info;
+
+       buf_size = header->num_clauses * 256 + debug_info_size + 1024 + (seq_points ? (seq_points->len * 64) : 0);
        p = buf = g_malloc (buf_size);
 
 #ifdef MONO_ARCH_HAVE_XP_UNWIND
        use_unwind_ops = cfg->unwind_ops != NULL;
 #endif
 
-       seq_points = cfg->seq_points;
-
        flags = (jinfo->has_generic_jit_info ? 1 : 0) | (use_unwind_ops ? 2 : 0) | (header->num_clauses ? 4 : 0) | (seq_points ? 8 : 0) | (cfg->compile_llvm ? 16 : 0);
 
        encode_value (flags, p, &p);
@@ -3169,17 +3169,22 @@ emit_exception_debug_info (MonoAotCompile *acfg, MonoCompile *cfg)
        }
 
        if (seq_points) {
-               int il_offset, native_offset, last_il_offset, last_native_offset;
+               int il_offset, native_offset, last_il_offset, last_native_offset, j;
 
                encode_value (seq_points->len, p, &p);
                last_il_offset = last_native_offset = 0;
-               for (i = 0; i < seq_points->len; i += 2) {
-                       il_offset = GPOINTER_TO_INT (g_ptr_array_index (seq_points, i));
-                       native_offset = GPOINTER_TO_INT (g_ptr_array_index (seq_points, i + 1));
+               for (i = 0; i < seq_points->len; ++i) {
+                       SeqPoint *sp = &seq_points->seq_points [i];
+                       il_offset = sp->il_offset;
+                       native_offset = sp->native_offset;
                        encode_value (il_offset - last_il_offset, p, &p);
                        encode_value (native_offset - last_native_offset, p, &p);
                        last_il_offset = il_offset;
                        last_native_offset = native_offset;
+
+                       encode_value (sp->next_len, p, &p);
+                       for (j = 0; j < sp->next_len; ++j)
+                               encode_value (sp->next [j], p, &p);
                }
        }
                
index d7fa52def1b00b8fbdf25304a9a0b2e48b188804..d46c980fab21243f605de4a19045073e7d67cfa4 100644 (file)
@@ -1964,19 +1964,25 @@ decode_exception_debug_info (MonoAotModule *amodule, MonoDomain *domain,
        }
 
        if (has_seq_points) {
-               GPtrArray *seq_points;
-               int il_offset, native_offset, last_il_offset, last_native_offset;
+               MonoSeqPointInfo *seq_points;
+               int il_offset, native_offset, last_il_offset, last_native_offset, j;
 
                int len = decode_value (p, &p);
 
-               seq_points = g_ptr_array_new ();
+               seq_points = g_malloc0 (sizeof (MonoSeqPointInfo) + (len - MONO_ZERO_LEN_ARRAY) * sizeof (SeqPoint));
                last_il_offset = last_native_offset = 0;
-               for (i = 0; i < len; i += 2) {
+               for (i = 0; i < len; ++i) {
+                       SeqPoint *sp = &seq_points->seq_points [i];
                        il_offset = last_il_offset + decode_value (p, &p);
                        native_offset = last_native_offset + decode_value (p, &p);
 
-                       g_ptr_array_add (seq_points, GINT_TO_POINTER (il_offset));
-                       g_ptr_array_add (seq_points, GINT_TO_POINTER (native_offset));
+                       sp->il_offset = il_offset;
+                       sp->native_offset = native_offset;
+                       
+                       sp->next_len = decode_value (p, &p);
+                       sp->next = g_new (int, sp->next_len);
+                       for (j = 0; j < sp->next_len; ++j)
+                               sp->next [j] = decode_value (p, &p);
 
                        last_il_offset = il_offset;
                        last_native_offset = native_offset;
index 0923fa2fc8015cf7bb4c3bb4b4e47c42b26f0879..3982519e7b96075c4626ea39038665f6ffc3471b 100644 (file)
@@ -439,7 +439,11 @@ typedef struct {
        gpointer start_sp;
        MonoMethod *last_method;
        int last_line;
-} MonoSingleStepReq;
+       /* Whenever single stepping is performed using start/stop_single_stepping () */
+       gboolean global;
+       /* The list of breakpoints used to implement step-over */
+       GSList *bps;
+} SingleStepReq;
 
 /* Dummy structure used for the profiler callbacks */
 typedef struct {
@@ -514,7 +518,7 @@ static mono_mutex_t debugger_thread_exited_mutex;
 static DebuggerProfiler debugger_profiler;
 
 /* The single step request instance */
-static MonoSingleStepReq *ss_req = NULL;
+static SingleStepReq *ss_req = NULL;
 static gpointer ss_invoke_addr = NULL;
 
 #ifdef MONO_ARCH_SOFT_DEBUG_SUPPORTED
@@ -568,8 +572,9 @@ static void ids_cleanup (void);
 
 static void suspend_init (void);
 
-static ErrorCode ss_start (MonoInternalThread *thread, StepSize size, StepDepth depth, EventRequest *req);
-static void ss_stop (EventRequest *req);
+static void ss_start (SingleStepReq *ss_req, MonoMethod *method, SeqPoint *sp, MonoSeqPointInfo *info);
+static ErrorCode ss_create (MonoInternalThread *thread, StepSize size, StepDepth depth, EventRequest *req);
+static void ss_destroy (SingleStepReq *req);
 
 static void start_debugger_thread (void);
 
@@ -2203,6 +2208,60 @@ is_suspended (void)
        return count_threads_to_wait_for () == 0;
 }
 
+/*
+ * find_seq_point_for_native_offset:
+ *
+ *   Find the sequence point corresponding to the native offset NATIVE_OFFSET, which
+ * should be the location of a sequence point.
+ */
+static SeqPoint*
+find_seq_point_for_native_offset (MonoDomain *domain, MonoMethod *method, gint32 native_offset, MonoSeqPointInfo **info)
+{
+       MonoSeqPointInfo *seq_points;
+       int i;
+
+       mono_domain_lock (domain);
+       seq_points = g_hash_table_lookup (domain_jit_info (domain)->seq_points, method);
+       mono_domain_unlock (domain);
+       g_assert (seq_points);
+
+       *info = seq_points;
+
+       for (i = 0; i < seq_points->len; ++i) {
+               if (seq_points->seq_points [i].native_offset == native_offset)
+                       return &seq_points->seq_points [i];
+       }
+
+       return NULL;
+}
+
+/*
+ * find_seq_point:
+ *
+ *   Find the sequence point corresponding to the IL offset IL_OFFSET, which
+ * should be the location of a sequence point.
+ */
+static SeqPoint*
+find_seq_point (MonoDomain *domain, MonoMethod *method, gint32 il_offset, MonoSeqPointInfo **info)
+{
+       MonoSeqPointInfo *seq_points;
+       int i;
+
+       mono_domain_lock (domain);
+       seq_points = g_hash_table_lookup (domain_jit_info (domain)->seq_points, method);
+       mono_domain_unlock (domain);
+       g_assert (seq_points);
+
+       *info = seq_points;
+
+       for (i = 0; i < seq_points->len; ++i) {
+               if (seq_points->seq_points [i].il_offset == il_offset)
+                       return &seq_points->seq_points [i];
+       }
+
+       return NULL;
+}
+
 /*
  * compute_il_offset:
  *
@@ -2214,7 +2273,7 @@ is_suspended (void)
 static gint32
 compute_il_offset (MonoDomain *domain, MonoMethod *method, gint32 native_offset)
 {
-       GPtrArray *seq_points;
+       MonoSeqPointInfo *seq_points;
        int i, last_il_offset, seq_il_offset, seq_native_offset;
 
        mono_domain_lock (domain);
@@ -2225,9 +2284,9 @@ compute_il_offset (MonoDomain *domain, MonoMethod *method, gint32 native_offset)
        last_il_offset = -1;
 
        /* Find the sequence point */
-       for (i = 0; i < seq_points->len; i += 2) {
-               seq_il_offset = GPOINTER_TO_UINT (g_ptr_array_index (seq_points, i));
-               seq_native_offset = GPOINTER_TO_UINT (g_ptr_array_index (seq_points, i + 1));
+       for (i = 0; i < seq_points->len; ++i) {
+               seq_il_offset = seq_points->seq_points [i].il_offset;
+               seq_native_offset = seq_points->seq_points [i].native_offset;
 
                if (seq_native_offset > native_offset)
                        break;
@@ -2796,9 +2855,9 @@ end_runtime_invoke (MonoProfiler *prof, MonoMethod *method)
                EventRequest *req = g_ptr_array_index (event_requests, i);
 
                if (req->event_kind == EVENT_KIND_STEP) {
-                       ss_stop (req);
-                        g_ptr_array_remove_index_fast (event_requests, i);
-                        g_free (req);
+                       ss_destroy (req->info);
+                       g_ptr_array_remove_index_fast (event_requests, i);
+                       g_free (req);
                        break;
                }
        }
@@ -2917,16 +2976,16 @@ breakpoints_cleanup (void)
  * JI.
  */
 static void
-insert_breakpoint (GPtrArray *seq_points, MonoJitInfo *ji, MonoBreakpoint *bp)
+insert_breakpoint (MonoSeqPointInfo *seq_points, MonoJitInfo *ji, MonoBreakpoint *bp)
 {
        int i, count;
        gint32 il_offset, native_offset;
        BreakpointInstance *inst;
 
        native_offset = 0;
-       for (i = 0; i < seq_points->len; i += 2) {
-               il_offset = GPOINTER_TO_INT (g_ptr_array_index (seq_points, i));
-               native_offset = GPOINTER_TO_INT (g_ptr_array_index (seq_points, i + 1));
+       for (i = 0; i < seq_points->len; ++i) {
+               il_offset = seq_points->seq_points [i].il_offset;
+               native_offset = seq_points->seq_points [i].native_offset;
 
                if (il_offset == bp->il_offset)
                        break;
@@ -2990,7 +3049,7 @@ static void
 add_pending_breakpoints (MonoMethod *method, MonoJitInfo *ji)
 {
        int i;
-       GPtrArray *seq_points;
+       MonoSeqPointInfo *seq_points;
        MonoDomain *domain;
 
        if (!breakpoints)
@@ -3020,7 +3079,7 @@ add_pending_breakpoints (MonoMethod *method, MonoJitInfo *ji)
 }
 
 static void
-set_bp_in_method (MonoDomain *domain, MonoMethod *method, GPtrArray *seq_points, MonoBreakpoint *bp)
+set_bp_in_method (MonoDomain *domain, MonoMethod *method, MonoSeqPointInfo *seq_points, MonoBreakpoint *bp)
 {
        gpointer code;
        MonoJitInfo *ji;
@@ -3042,7 +3101,7 @@ static void
 set_bp_in_method_cb (gpointer key, gpointer value, gpointer user_data)
 {
        MonoMethod *method = key;
-       GPtrArray *seq_points = value;
+       MonoSeqPointInfo *seq_points = value;
        MonoBreakpoint *bp = user_data;
        MonoDomain *domain = mono_domain_get ();
 
@@ -3068,7 +3127,7 @@ set_bp_in_method_cb (gpointer key, gpointer value, gpointer user_data)
 static MonoBreakpoint*
 set_breakpoint (MonoMethod *method, long il_offset, EventRequest *req)
 {
-       GPtrArray *seq_points;
+       MonoSeqPointInfo *seq_points;
        MonoDomain *domain;
        MonoBreakpoint *bp;
 
@@ -3085,7 +3144,7 @@ set_breakpoint (MonoMethod *method, long il_offset, EventRequest *req)
        bp->req = req;
        bp->children = g_ptr_array_new ();
 
-       DEBUG(1, fprintf (log_file, "[dbg] Setting breakpoint at %s:0x%x.\n", method ? mono_method_full_name (method, TRUE) : "<all>", (int)il_offset));
+       DEBUG(1, fprintf (log_file, "[dbg] Setting %sbreakpoint at %s:0x%x.\n", (req->event_kind == EVENT_KIND_STEP) ? "single step " : "", method ? mono_method_full_name (method, TRUE) : "<all>", (int)il_offset));
 
        domain = mono_domain_get ();
        mono_domain_lock (domain);
@@ -3145,8 +3204,8 @@ process_breakpoint_inner (DebuggerTlsData *tls, MonoContext *ctx)
        guint32 native_offset;
        MonoBreakpoint *bp;
        BreakpointInstance *inst;
-       GPtrArray *reqs;
-       GSList *events = NULL;
+       GPtrArray *bp_reqs, *ss_reqs_orig, *ss_reqs;
+       GSList *bp_events = NULL, *ss_events = NULL, *enter_leave_events = NULL;
        EventKind kind = EVENT_KIND_BREAKPOINT;
 
        // FIXME: Speed this up
@@ -3172,7 +3231,9 @@ process_breakpoint_inner (DebuggerTlsData *tls, MonoContext *ctx)
        if (ji->method->wrapper_type || tls->disable_breakpoints)
                return;
 
-       reqs = g_ptr_array_new ();
+       bp_reqs = g_ptr_array_new ();
+       ss_reqs = g_ptr_array_new ();
+       ss_reqs_orig = g_ptr_array_new ();
 
        DEBUG(1, fprintf (log_file, "[%p] Breakpoint hit, method=%s, offset=0x%x.\n", (gpointer)GetCurrentThreadId (), ji->method->name, native_offset));
 
@@ -3187,12 +3248,17 @@ process_breakpoint_inner (DebuggerTlsData *tls, MonoContext *ctx)
 
                for (j = 0; j < bp->children->len; ++j) {
                        inst = g_ptr_array_index (bp->children, j);
-                       if (inst->ji == ji && inst->native_offset == native_offset)
-                               g_ptr_array_add (reqs, bp->req);
+                       if (inst->ji == ji && inst->native_offset == native_offset) {
+                               if (bp->req->event_kind == EVENT_KIND_STEP) {
+                                       g_ptr_array_add (ss_reqs_orig, bp->req);
+                               } else {
+                                       g_ptr_array_add (bp_reqs, bp->req);
+                               }
+                       }
                }
        }
-       if (reqs->len == 0) {
-               GPtrArray *seq_points;
+       if (bp_reqs->len == 0 && ss_reqs_orig->len == 0) {
+               MonoSeqPointInfo *seq_points;
                int seq_il_offset, seq_native_offset;
                MonoDomain *domain = mono_domain_get ();
 
@@ -3207,9 +3273,9 @@ process_breakpoint_inner (DebuggerTlsData *tls, MonoContext *ctx)
                }
                g_assert (seq_points);
 
-               for (i = 0; i < seq_points->len; i += 2) {
-                       seq_il_offset = GPOINTER_TO_INT (g_ptr_array_index (seq_points, i));
-                       seq_native_offset = GPOINTER_TO_INT (g_ptr_array_index (seq_points, i + 1));
+               for (i = 0; i < seq_points->len; ++i) {
+                       seq_il_offset = seq_points->seq_points [i].il_offset;
+                       seq_native_offset = seq_points->seq_points [i].native_offset;
 
                        if (native_offset == seq_native_offset) {
                                if (seq_il_offset == METHOD_ENTRY_IL_OFFSET)
@@ -3220,18 +3286,68 @@ process_breakpoint_inner (DebuggerTlsData *tls, MonoContext *ctx)
                        }
                }
        }
-       
-       if (reqs->len > 0)
-               events = create_event_list (EVENT_KIND_BREAKPOINT, reqs, ji, NULL, &suspend_policy);
-       else if (kind != EVENT_KIND_BREAKPOINT)
-               events = create_event_list (kind, NULL, ji, NULL, &suspend_policy);
 
-       g_ptr_array_free (reqs, TRUE);
+       /* Process single step requests */
+       for (i = 0; i < ss_reqs_orig->len; ++i) {
+               EventRequest *req = g_ptr_array_index (ss_reqs_orig, i);
+               SingleStepReq *ss_req = bp->req->info;
+               gboolean hit = TRUE;
+               MonoSeqPointInfo *info;
+               SeqPoint *sp;
+
+               sp = find_seq_point_for_native_offset (mono_domain_get (), ji->method, native_offset, &info);
+               g_assert (sp);
+
+               if (ss_req->size == STEP_SIZE_LINE) {
+                       /* Have to check whenever a different source line was reached */
+                       MonoDebugMethodInfo *minfo;
+                       MonoDebugSourceLocation *loc = NULL;
+
+                       minfo = mono_debug_lookup_method (ji->method);
+
+                       if (minfo)
+                               loc = mono_debug_symfile_lookup_location (minfo, sp->il_offset);
+
+                       if (!loc || (loc && ji->method == ss_req->last_method && loc->row == ss_req->last_line))
+                               /* Have to continue single stepping */
+                               hit = FALSE;
+                               
+                       if (loc) {
+                               ss_req->last_method = ji->method;
+                               ss_req->last_line = loc->row;
+                               mono_debug_free_source_location (loc);
+                       }
+               }
+
+               if (hit)
+                       g_ptr_array_add (ss_reqs, req);
+
+               /* Start single stepping again from the current sequence point */
+               ss_start (ss_req, ji->method, sp, info);
+       }
+       
+       if (ss_reqs->len > 0)
+               ss_events = create_event_list (EVENT_KIND_STEP, ss_reqs, ji, NULL, &suspend_policy);
+       if (bp_reqs->len > 0)
+               bp_events = create_event_list (EVENT_KIND_BREAKPOINT, bp_reqs, ji, NULL, &suspend_policy);
+       if (kind != EVENT_KIND_BREAKPOINT)
+               enter_leave_events = create_event_list (kind, NULL, ji, NULL, &suspend_policy);
 
        mono_loader_unlock ();
 
-       if (events)
-               process_event (kind, ji->method, 0, ctx, events, suspend_policy);
+       g_ptr_array_free (bp_reqs, TRUE);
+       g_ptr_array_free (ss_reqs, TRUE);
+
+       /* 
+        * FIXME: The first event will suspend, so the second will only be sent after the
+        * resume.
+        */
+       if (ss_events)
+               process_event (EVENT_KIND_STEP, ji->method, 0, ctx, ss_events, suspend_policy);
+       if (bp_events)
+               process_event (kind, ji->method, 0, ctx, bp_events, suspend_policy);
+       if (enter_leave_events)
+               process_event (kind, ji->method, 0, ctx, enter_leave_events, suspend_policy);
 }
 
 static void
@@ -3535,13 +3651,83 @@ stop_single_stepping (void)
 #endif
 }
 
+/*
+ * ss_stop:
+ *
+ *   Stop the single stepping operation given by SS_REQ.
+ */
+static void
+ss_stop (SingleStepReq *ss_req)
+{
+       gboolean use_bps = FALSE;
+
+       if (ss_req->bps) {
+               GSList *l;
+
+               use_bps = TRUE;
+
+               for (l = ss_req->bps; l; l = l->next) {
+                       clear_breakpoint (l->data);
+               }
+               g_slist_free (ss_req->bps);
+               ss_req->bps = NULL;
+       }
+
+       if (ss_req->global) {
+               stop_single_stepping ();
+               ss_req->global = FALSE;
+       }
+}
+
+/*
+ * ss_start:
+ *
+ *   Start the single stepping operation given by SS_REQ from the sequence point SP.
+ */
+static void
+ss_start (SingleStepReq *ss_req, MonoMethod *method, SeqPoint *sp, MonoSeqPointInfo *info)
+{
+       gboolean use_bp = FALSE;
+       int i;
+       SeqPoint *next_sp;
+       MonoBreakpoint *bp;
+
+       /* Stop the previous operation */
+       ss_stop (ss_req);
+
+       /*
+        * Implement single stepping using breakpoints if possible.
+        */
+       if (ss_req->depth == STEP_DEPTH_OVER) {
+               if (sp->next_len > 0) {
+                       use_bp = TRUE;
+                       for (i = 0; i < sp->next_len; ++i) {
+                               next_sp = &info->seq_points [sp->next [i]];
+
+                               bp = set_breakpoint (method, next_sp->il_offset, ss_req->req);
+                               ss_req->bps = g_slist_append (ss_req->bps, bp);
+                       }
+               }
+       }
+
+       if (!ss_req->bps) {
+               ss_req->global = TRUE;
+               start_single_stepping ();
+       } else {
+               ss_req->global = FALSE;
+       }
+}
+
 /*
  * Start single stepping of thread THREAD
  */
 static ErrorCode
-ss_start (MonoInternalThread *thread, StepSize size, StepDepth depth, EventRequest *req)
+ss_create (MonoInternalThread *thread, StepSize size, StepDepth depth, EventRequest *req)
 {
        DebuggerTlsData *tls;
+       MonoSeqPointInfo *info;
+       SeqPoint *sp = NULL;
+       MonoMethod *method = NULL;
 
        if (suspend_count == 0)
                return ERR_NOT_SUSPENDED;
@@ -3554,7 +3740,7 @@ ss_start (MonoInternalThread *thread, StepSize size, StepDepth depth, EventReque
                return ERR_NOT_IMPLEMENTED;
        }
 
-       ss_req = g_new0 (MonoSingleStepReq, 1);
+       ss_req = g_new0 (SingleStepReq, 1);
        ss_req->req = req;
        ss_req->thread = thread;
        ss_req->size = size;
@@ -3592,22 +3778,37 @@ ss_start (MonoInternalThread *thread, StepSize size, StepDepth depth, EventReque
                }
        }
 
-       start_single_stepping ();
+       if (ss_req->depth == STEP_DEPTH_OVER) {
+               StackFrame *frame;
+
+               compute_frame_info (thread, tls);
+
+               g_assert (tls->frame_count);
+               frame = tls->frames [0];
+
+               if (frame->il_offset != -1) {
+                       /* FIXME: Sort the table and use a binary search */
+                       sp = find_seq_point (frame->domain, frame->method, frame->il_offset, &info);
+                       g_assert (sp);
+                       method = frame->method;
+               }
+       }
+
+       ss_start (ss_req, method, sp, info);
 
        return 0;
 }
 
 static void
-ss_stop (EventRequest *req)
+ss_destroy (SingleStepReq *req)
 {
        // FIXME: Locking
-       g_assert (ss_req);
-       g_assert (ss_req->req == req);
+       g_assert (ss_req == req);
+
+       ss_stop (ss_req);
 
        g_free (ss_req);
        ss_req = NULL;
-
-       stop_single_stepping ();
 }
 
 void
@@ -4025,7 +4226,7 @@ clear_event_request (int req_id, int etype)
                        if (req->event_kind == EVENT_KIND_BREAKPOINT)
                                clear_breakpoint (req->info);
                        if (req->event_kind == EVENT_KIND_STEP)
-                               ss_stop (req);
+                               ss_destroy (req->info);
                        if (req->event_kind == EVENT_KIND_METHOD_ENTRY)
                                clear_breakpoint (req->info);
                        if (req->event_kind == EVENT_KIND_METHOD_EXIT)
@@ -4580,7 +4781,7 @@ event_commands (int command, guint8 *p, guint8 *end, Buffer *buf)
                                return err;
                        }
 
-                       err = ss_start (THREAD_TO_INTERNAL (step_thread), size, depth, req);
+                       err = ss_create (THREAD_TO_INTERNAL (step_thread), size, depth, req);
                        if (err) {
                                g_free (req);
                                return err;
index 30df6fac585bff9c287090aecaf52805ba9f5564..794e4d6d8b822f6b36f829d3b74af6cd00cc464e 100644 (file)
@@ -3509,7 +3509,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                case OP_NOT_NULL:
                        break;
                case OP_SEQ_POINT: {
-                       int i, il_offset;
+                       int i;
 
                        if (cfg->compile_aot)
                                NOT_IMPLEMENTED;
@@ -3525,12 +3525,8 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        if (ins->flags & MONO_INST_SINGLE_STEP_LOC)
                                amd64_mov_reg_mem (code, AMD64_R11, (guint64)ss_trigger_page, 4);
 
-                       il_offset = ins->inst_imm;
+                       mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
 
-                       if (!cfg->seq_points)
-                               cfg->seq_points = g_ptr_array_new ();
-                       g_ptr_array_add (cfg->seq_points, GUINT_TO_POINTER (il_offset));
-                       g_ptr_array_add (cfg->seq_points, GUINT_TO_POINTER (code - cfg->native_code));
                        /* 
                         * A placeholder for a possible breakpoint inserted by
                         * mono_arch_set_breakpoint ().
index d96f34fb31cdb829dec0fc38806e4a876fc6f1fc..84f3ee1d4450a8a0ec8a0874c59f9623704fee07 100644 (file)
@@ -3239,7 +3239,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                case OP_NOT_NULL:
                        break;
                case OP_SEQ_POINT: {
-                       int i, il_offset;
+                       int i;
                        MonoInst *info_var = cfg->arch.seq_point_info_var;
                        MonoInst *ss_trigger_page_var = cfg->arch.ss_trigger_page_var;
                        MonoInst *var;
@@ -3281,12 +3281,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                                ARM_LDR_IMM (code, dreg, dreg, 0);
                        }
 
-                       il_offset = ins->inst_imm;
-
-                       if (!cfg->seq_points)
-                               cfg->seq_points = g_ptr_array_new ();
-                       g_ptr_array_add (cfg->seq_points, GUINT_TO_POINTER (il_offset));
-                       g_ptr_array_add (cfg->seq_points, GUINT_TO_POINTER (code - cfg->native_code));
+                       mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
 
                        if (cfg->compile_aot) {
                                guint32 offset = code - cfg->native_code;
index ddb29c4f50f9762229335f8a2a849c7be8c8fabe..7e68a6a060a09415210725ba9a9f42f43b626d0d 100644 (file)
@@ -3281,7 +3281,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                case OP_NOT_NULL:
                        break;
                case OP_SEQ_POINT: {
-                       int i, il_offset;
+                       int i;
 
                        if (cfg->compile_aot)
                                NOT_IMPLEMENTED;
@@ -3297,12 +3297,8 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                                ppc_ldptr (code, ppc_r11, 0, ppc_r11);
                        }
 
-                       il_offset = ins->inst_imm;
+                       mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
 
-                       if (!cfg->seq_points)
-                               cfg->seq_points = g_ptr_array_new ();
-                       g_ptr_array_add (cfg->seq_points, GUINT_TO_POINTER (il_offset));
-                       g_ptr_array_add (cfg->seq_points, GUINT_TO_POINTER (code - cfg->native_code));
                        /* 
                         * A placeholder for a possible breakpoint inserted by
                         * mono_arch_set_breakpoint ().
index 44e0e081e3b85bdd4ca5dc158c4b9f97d2f3fff8..e0f010dc451871d157c31f40737ce7af42a64fac 100644 (file)
@@ -2374,7 +2374,7 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                case OP_NOT_NULL:
                        break;
                case OP_SEQ_POINT: {
-                       int i, il_offset;
+                       int i;
 
                        if (cfg->compile_aot)
                                NOT_IMPLEMENTED;
@@ -2388,12 +2388,8 @@ mono_arch_output_basic_block (MonoCompile *cfg, MonoBasicBlock *bb)
                        if (ins->flags & MONO_INST_SINGLE_STEP_LOC)
                                x86_alu_reg_mem (code, X86_CMP, X86_EAX, (guint32)ss_trigger_page);
 
-                       il_offset = ins->inst_imm;
+                       mono_add_seq_point (cfg, bb, ins, code - cfg->native_code);
 
-                       if (!cfg->seq_points)
-                               cfg->seq_points = g_ptr_array_new ();
-                       g_ptr_array_add (cfg->seq_points, GUINT_TO_POINTER (il_offset));
-                       g_ptr_array_add (cfg->seq_points, GUINT_TO_POINTER (code - cfg->native_code));
                        /* 
                         * A placeholder for a possible breakpoint inserted by
                         * mono_arch_set_breakpoint ().
index eb9fb3dc879345697ffa489f101a0bd407d32054..dfea01afccbc1ea66cc4559ba9c3fac9b51081ca 100644 (file)
@@ -2835,6 +2835,15 @@ mono_resolve_patch_target (MonoMethod *method, MonoDomain *domain, guint8 *code,
        return (gpointer)target;
 }
 
+void
+mono_add_seq_point (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *ins, int native_offset)
+{
+       ins->inst_offset = native_offset;
+       g_ptr_array_add (cfg->seq_points, ins);
+       bb->seq_points = g_slist_prepend_mempool (cfg->mempool, bb->seq_points, ins);
+       bb->last_seq_point = ins;
+}
+
 static void
 mono_compile_create_vars (MonoCompile *cfg)
 {
@@ -3000,6 +3009,90 @@ mono_postprocess_patches (MonoCompile *cfg)
        }
 }
 
+static void
+mono_save_seq_point_info (MonoCompile *cfg)
+{
+       MonoBasicBlock *bb, *in_bb;
+       GSList *bb_seq_points, *l;
+       MonoInst *last;
+       MonoDomain *domain = cfg->domain;
+       int i;
+       MonoSeqPointInfo *info;
+       GSList **next;
+
+       if (!cfg->seq_points)
+               return;
+
+       info = g_malloc0 (sizeof (MonoSeqPointInfo) + (cfg->seq_points->len - MONO_ZERO_LEN_ARRAY) * sizeof (SeqPoint));
+       info->len = cfg->seq_points->len;
+       for (i = 0; i < cfg->seq_points->len; ++i) {
+               SeqPoint *sp = &info->seq_points [i];
+               MonoInst *ins = g_ptr_array_index (cfg->seq_points, i);
+
+               sp->il_offset = ins->inst_imm;
+               sp->native_offset = ins->inst_offset;
+
+               /* Used below */
+               ins->backend.size = i;
+       }
+
+       /*
+        * For each sequence point, compute the list of sequence points immediately
+        * following it, this is needed to implement 'step over' in the debugger agent.
+        */ 
+       next = g_new0 (GSList*, cfg->seq_points->len);
+       for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
+               bb_seq_points = g_slist_reverse (bb->seq_points);
+               last = NULL;
+               for (l = bb_seq_points; l; l = l->next) {
+                       MonoInst *ins = l->data;
+                               
+                       if (last != NULL) {
+                               /* Link with the previous seq point in the same bb */
+                               next [last->backend.size] = g_slist_append (next [last->backend.size], GUINT_TO_POINTER (ins->backend.size));
+                       } else {
+                               /* Link with the last bb in the previous bblocks */
+                               /* 
+                                * FIXME: What if the prev bb doesn't have a seq point, but
+                                * one of its predecessors has ?
+                                */
+                               for (i = 0; i < bb->in_count; ++i) {
+                                       in_bb = bb->in_bb [i];
+
+                                       if (in_bb->last_seq_point)
+                                               next [in_bb->last_seq_point->backend.size] = g_slist_append (next [in_bb->last_seq_point->backend.size], GUINT_TO_POINTER (ins->backend.size));
+                               }
+                       }
+
+                       last = ins;
+               }
+       }
+
+       for (i = 0; i < cfg->seq_points->len; ++i) {
+               SeqPoint *sp = &info->seq_points [i];
+               GSList *l;
+               int j;
+
+               sp->next_len = g_slist_length (next [i]);
+               sp->next = g_new (int, sp->next_len);
+               j = 0;
+               for (l = next [i]; l; l = l->next)
+                       sp->next [j ++] = GPOINTER_TO_UINT (l->data);
+               g_slist_free (next [i]);
+       }
+       g_free (next);
+
+       cfg->seq_point_info = info;
+
+       // FIXME: dynamic methods
+       mono_domain_lock (domain);
+       g_hash_table_insert (domain_jit_info (domain)->seq_points, cfg->method_to_register, info);
+       mono_domain_unlock (domain);
+
+       g_ptr_array_free (cfg->seq_points, TRUE);
+       cfg->seq_points = NULL;
+}
+
 void
 mono_codegen (MonoCompile *cfg)
 {
@@ -3254,6 +3347,9 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
        cfg->compile_llvm = try_llvm;
        cfg->token_info_hash = g_hash_table_new (NULL, NULL);
 
+       if (cfg->gen_seq_points)
+               cfg->seq_points = g_ptr_array_new ();
+
        if (cfg->compile_aot && !try_generic_shared && (method->is_generic || method->klass->generic_container)) {
                cfg->exception_type = MONO_EXCEPTION_GENERIC_SHARING_FAILED;
                return cfg;
@@ -4045,12 +4141,7 @@ mini_method_compile (MonoMethod *method, guint32 opts, MonoDomain *domain, gbool
 
        mini_gc_create_gc_map (cfg);
  
-       if (cfg->seq_points) {
-               // FIXME: dynamic methods
-               mono_domain_lock (domain);
-               g_hash_table_insert (domain_jit_info (domain)->seq_points, method_to_register, cfg->seq_points);
-               mono_domain_unlock (domain);
-       }
+       mono_save_seq_point_info (cfg);
 
        if (!cfg->compile_aot) {
                mono_domain_lock (cfg->domain);
@@ -4985,6 +5076,8 @@ mini_parse_debug_options (void)
                        debug_options.gdb = TRUE;
                else if (!strcmp (arg, "explicit-null-checks"))
                        debug_options.explicit_null_checks = TRUE;
+               else if (!strcmp (arg, "gen-seq-points"))
+                       debug_options.gen_seq_points = TRUE;
                else {
                        fprintf (stderr, "Invalid option for the MONO_DEBUG env variable: %s\n", arg);
                        fprintf (stderr, "Available options: 'handle-sigint', 'keep-delegates', 'collect-pagefault-stats', 'break-on-unverified', 'no-gdb-backtrace', 'dont-free-domains', 'suspend-on-sigsegv', 'dyn-runtime-invoke', 'gdb', 'explicit-null-checks'\n");
index 3a0232d04da1393d60f0c3469a5123ada184d390..6f084518230e3b92f295086344cdaa3d610a54b1 100644 (file)
@@ -89,7 +89,7 @@ typedef gint64 mgreg_t;
 #endif
 
 /* Version number of the AOT file format */
-#define MONO_AOT_FILE_VERSION "65"
+#define MONO_AOT_FILE_VERSION "66"
 
 //TODO: This is x86/amd64 specific.
 #define mono_simd_shuffle_mask(a,b,c,d) ((a) | ((b) << 2) | ((c) << 4) | ((d) << 6))
@@ -214,6 +214,19 @@ typedef struct {
        gpointer lmf;
 } StackFrameInfo;
 
+typedef struct {
+       int il_offset, native_offset;
+       /* Indexes of successor sequence points */
+       int *next;
+       /* Number of entries in next */
+       int next_len;
+} SeqPoint;
+
+typedef struct {
+       int len;
+       SeqPoint seq_points [MONO_ZERO_LEN_ARRAY];
+} MonoSeqPointInfo;
+
 #if 0
 #define mono_bitset_foreach_bit(set,b,n) \
        for (b = 0; b < n; b++)\
@@ -359,7 +372,6 @@ typedef struct MonoInstList MonoInstList;
 typedef struct MonoInst MonoInst;
 typedef struct MonoCallInst MonoCallInst;
 typedef struct MonoCallArgParm MonoCallArgParm;
-typedef struct MonoEdge MonoEdge;
 typedef struct MonoMethodVar MonoMethodVar;
 typedef struct MonoBasicBlock MonoBasicBlock;
 typedef struct MonoLMF MonoLMF;
@@ -402,12 +414,6 @@ extern const gint8 ins_sreg_counts [];
 
 #define mono_bb_first_ins(bb) (bb)->code
 
-struct MonoEdge {
-       MonoEdge *next;
-       MonoBasicBlock *bb;
-       /* add edge type? */
-};
-
 struct MonoSpillInfo {
        int offset;
 };
@@ -470,7 +476,6 @@ struct MonoBasicBlock {
        GSList *dominated;
        /* fast dominator algorithm */
        MonoBasicBlock *df_parent, *ancestor, *child, *label;
-       MonoEdge *bucket;
        int size, sdom, idomn;
        
        /* loop nesting and recognition */
@@ -508,6 +513,9 @@ struct MonoBasicBlock {
        /* we use that to prevent merging of bblocks covered by different clauses*/
        guint real_offset;
 
+       GSList *seq_points;
+       MonoInst *last_seq_point;
+
        /*
         * The region encodes whether the basic block is inside
         * a finally, catch, filter or none of these.
@@ -1111,6 +1119,9 @@ typedef struct {
         */
        GPtrArray *seq_points;
 
+       /* The encoded sequence point info */
+       MonoSeqPointInfo *seq_point_info;
+
        /* Used by AOT */
        guint32 got_offset, ex_info_offset, method_info_offset;
 
@@ -1465,6 +1476,7 @@ void        mono_print_ins (MonoInst *ins) MONO_INTERNAL;
 gboolean  mini_assembly_can_skip_verification (MonoDomain *domain, MonoMethod *method) MONO_INTERNAL;
 gboolean  mini_method_verify (MonoCompile *cfg, MonoMethod *method) MONO_INTERNAL;
 MonoInst *mono_get_got_var (MonoCompile *cfg) MONO_INTERNAL;
+void      mono_add_seq_point (MonoCompile *cfg, MonoBasicBlock *bb, MonoInst *ins, int native_offset) MONO_INTERNAL;
 
 gboolean  mini_class_is_system_array (MonoClass *klass) MONO_INTERNAL;
 MonoMethodSignature *mono_get_element_address_signature (int arity) MONO_INTERNAL;