genmdesc_SOURCES = \
mini.h \
+ seq-points.h \
genmdesc.c \
helpers.c \
../metadata/opcodes.c
common_sources = \
mini.c \
+ seq-points.c \
+ seq-points.h \
ir-emit.h \
method-to-ir.c \
decompose.c \
#include <mono/utils/mono-mmap.h>
#include "mini.h"
+#include "seq-points.h"
#include "image-writer.h"
#include "dwarfwriter.h"
#include "mini-gc.h"
#include <mono/utils/mono-digest.h>
#include "mini.h"
+#include "seq-points.h"
#include "version.h"
#ifndef DISABLE_AOT
#include <mono/utils/mono-threads.h>
#include "debugger-agent.h"
#include "mini.h"
+#include "seq-points.h"
/*
On iOS we can't use System.Environment.Exit () as it will do the wrong
return count_threads_to_wait_for () == 0;
}
-static MonoSeqPointInfo*
-get_seq_points (MonoDomain *domain, MonoMethod *method)
-{
- MonoSeqPointInfo *seq_points;
-
- mono_domain_lock (domain);
- seq_points = g_hash_table_lookup (domain_jit_info (domain)->seq_points, method);
- if (!seq_points && method->is_inflated) {
- /* generic sharing + aot */
- seq_points = g_hash_table_lookup (domain_jit_info (domain)->seq_points, mono_method_get_declaring_generic_method (method));
- if (!seq_points)
- seq_points = g_hash_table_lookup (domain_jit_info (domain)->seq_points, mini_get_shared_method (method));
- }
- mono_domain_unlock (domain);
-
- return seq_points;
-}
-
static void
no_seq_points_found (MonoMethod *method)
{
printf ("Unable to find seq points for method '%s'.\n", mono_method_full_name (method, TRUE));
}
-/*
- * find_next_seq_point_for_native_offset:
- *
- * Find the first sequence point after NATIVE_OFFSET.
- */
-static SeqPoint*
-find_next_seq_point_for_native_offset (MonoDomain *domain, MonoMethod *method, gint32 native_offset, MonoSeqPointInfo **info)
-{
- MonoSeqPointInfo *seq_points;
- int i;
-
- seq_points = get_seq_points (domain, method);
- if (!seq_points) {
- if (info)
- *info = NULL;
- return NULL;
- }
- g_assert (seq_points);
- if (info)
- *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_prev_seq_point_for_native_offset:
- *
- * Find the first sequence point before NATIVE_OFFSET.
- */
-static SeqPoint*
-find_prev_seq_point_for_native_offset (MonoDomain *domain, MonoMethod *method, gint32 native_offset, MonoSeqPointInfo **info)
-{
- MonoSeqPointInfo *seq_points;
- int i;
-
- seq_points = get_seq_points (domain, method);
- if (info)
- *info = seq_points;
- if (!seq_points)
- return NULL;
-
- for (i = seq_points->len - 1; i >= 0; --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 G_GNUC_UNUSED SeqPoint*
-find_seq_point (MonoDomain *domain, MonoMethod *method, gint32 il_offset, MonoSeqPointInfo **info)
-{
- MonoSeqPointInfo *seq_points;
- int i;
-
- *info = NULL;
-
- seq_points = get_seq_points (domain, method);
- if (!seq_points)
- return NULL;
- *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;
-}
-
typedef struct {
DebuggerTlsData *tls;
GSList *frames;
#include "mini.h"
-/* IL offsets used to mark the sequence points belonging to method entry/exit events */
-#define METHOD_ENTRY_IL_OFFSET -1
-#define METHOD_EXIT_IL_OFFSET 0xffffff
-
-/* Native offset used to mark seq points in dead code */
-#define SEQ_POINT_NATIVE_OFFSET_DEAD_CODE -1
-
void
mono_debugger_agent_parse_options (char *options) MONO_INTERNAL;
#include "jit-icalls.h"
#include "jit.h"
#include "debugger-agent.h"
+#include "seq-points.h"
#define BRANCH_COST 10
#define INLINE_LENGTH_LIMIT 20
#include <mono/utils/mono-threads.h>
#include "mini.h"
+#include "seq-points.h"
#include "mini-llvm.h"
#include "tasklets.h"
#include <string.h>
#include "mini-gc.h"
#include "debugger-agent.h"
+#include "seq-points.h"
static gpointer mono_jit_compile_method_with_opt (MonoMethod *method, guint32 opt, MonoException **ex);
}
}
-static void
-collect_pred_seq_points (MonoBasicBlock *bb, MonoInst *ins, GSList **next, int depth)
-{
- int i;
- MonoBasicBlock *in_bb;
- GSList *l;
-
- for (i = 0; i < bb->in_count; ++i) {
- in_bb = bb->in_bb [i];
-
- if (in_bb->last_seq_point) {
- int src_index = in_bb->last_seq_point->backend.size;
- int dst_index = ins->backend.size;
-
- /* 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));
- } else {
- /* Have to look at its predecessors */
- if (depth < 5)
- collect_pred_seq_points (in_bb, ins, next, depth + 1);
- }
- }
-}
-
-static void
-mono_save_seq_point_info (MonoCompile *cfg)
-{
- MonoBasicBlock *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 * 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;
- if (ins->flags & MONO_INST_NONEMPTY_STACK)
- sp->flags |= MONO_SEQ_POINT_FLAG_NONEMPTY_STACK;
-
- /* 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 (ins->inst_imm == METHOD_ENTRY_IL_OFFSET || ins->inst_imm == METHOD_EXIT_IL_OFFSET)
- /* Used to implement method entry/exit events */
- continue;
- if (ins->inst_offset == SEQ_POINT_NATIVE_OFFSET_DEAD_CODE)
- continue;
-
- 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 */
- collect_pred_seq_points (bb, ins, next, 0);
- }
-
- last = ins;
- }
-
- if (bb->last_ins && bb->last_ins->opcode == OP_ENDFINALLY && bb->seq_points) {
- MonoBasicBlock *bb2;
- MonoInst *endfinally_seq_point = NULL;
-
- /*
- * The ENDFINALLY branches are not represented in the cfg, so link it with all seq points starting bbs.
- */
- l = g_slist_last (bb->seq_points);
- if (l) {
- endfinally_seq_point = l->data;
-
- for (bb2 = cfg->bb_entry; bb2; bb2 = bb2->next_bb) {
- GSList *l = g_slist_last (bb2->seq_points);
-
- if (l) {
- MonoInst *ins = l->data;
-
- if (!(ins->inst_imm == METHOD_ENTRY_IL_OFFSET || ins->inst_imm == METHOD_EXIT_IL_OFFSET) && ins != endfinally_seq_point)
- next [endfinally_seq_point->backend.size] = g_slist_append (next [endfinally_seq_point->backend.size], GUINT_TO_POINTER (ins->backend.size));
- }
- }
- }
- }
- }
-
- if (cfg->verbose_level > 2) {
- printf ("\nSEQ POINT MAP: \n");
- }
-
- for (i = 0; i < cfg->seq_points->len; ++i) {
- SeqPoint *sp = &info->seq_points [i];
- GSList *l;
- int j, next_index;
-
- sp->next_len = g_slist_length (next [i]);
- sp->next = g_new (int, sp->next_len);
- j = 0;
- if (cfg->verbose_level > 2 && next [i]) {
- printf ("\tIL0x%x ->", sp->il_offset);
- for (l = next [i]; l; l = l->next) {
- next_index = GPOINTER_TO_UINT (l->data);
- printf (" IL0x%x", info->seq_points [next_index].il_offset);
- }
- printf ("\n");
- }
- for (l = next [i]; l; l = l->next) {
- next_index = GPOINTER_TO_UINT (l->data);
- sp->next [j ++] = next_index;
- }
- g_slist_free (next [i]);
- }
- g_free (next);
-
- cfg->seq_point_info = info;
-
- // FIXME: dynamic methods
- if (!cfg->compile_aot) {
- mono_domain_lock (domain);
- // FIXME: How can the lookup succeed ?
- if (!g_hash_table_lookup (domain_jit_info (domain)->seq_points, cfg->method_to_register))
- 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)
{
*/
typedef MonoStackFrameInfo StackFrameInfo;
-#define MONO_SEQ_POINT_FLAG_NONEMPTY_STACK 1
-
-typedef struct {
- int il_offset, native_offset, flags;
- /* 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++)\
GPtrArray *seq_points;
/* The encoded sequence point info */
- MonoSeqPointInfo *seq_point_info;
+ struct MonoSeqPointInfo *seq_point_info;
/* Method headers which need to be freed after compilation */
GSList *headers_to_free;
--- /dev/null
+/*
+ * seq-points.c: Sequence Points functions
+ *
+ * Authors:
+ * Marcos Henrich (marcos.henrich@xamarin.com)
+ *
+ * Copyright 2014 Xamarin, Inc (http://www.xamarin.com)
+ */
+
+#include "mini.h"
+#include "seq-points.h"
+
+static void
+collect_pred_seq_points (MonoBasicBlock *bb, MonoInst *ins, GSList **next, int depth)
+{
+ int i;
+ MonoBasicBlock *in_bb;
+ GSList *l;
+
+ for (i = 0; i < bb->in_count; ++i) {
+ in_bb = bb->in_bb [i];
+
+ if (in_bb->last_seq_point) {
+ int src_index = in_bb->last_seq_point->backend.size;
+ int dst_index = ins->backend.size;
+
+ /* 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));
+ } else {
+ /* Have to look at its predecessors */
+ if (depth < 5)
+ collect_pred_seq_points (in_bb, ins, next, depth + 1);
+ }
+ }
+}
+
+void
+mono_save_seq_point_info (MonoCompile *cfg)
+{
+ MonoBasicBlock *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 * 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;
+ if (ins->flags & MONO_INST_NONEMPTY_STACK)
+ sp->flags |= MONO_SEQ_POINT_FLAG_NONEMPTY_STACK;
+
+ /* 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 (ins->inst_imm == METHOD_ENTRY_IL_OFFSET || ins->inst_imm == METHOD_EXIT_IL_OFFSET)
+ /* Used to implement method entry/exit events */
+ continue;
+ if (ins->inst_offset == SEQ_POINT_NATIVE_OFFSET_DEAD_CODE)
+ continue;
+
+ 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 */
+ collect_pred_seq_points (bb, ins, next, 0);
+ }
+
+ last = ins;
+ }
+
+ if (bb->last_ins && bb->last_ins->opcode == OP_ENDFINALLY && bb->seq_points) {
+ MonoBasicBlock *bb2;
+ MonoInst *endfinally_seq_point = NULL;
+
+ /*
+ * The ENDFINALLY branches are not represented in the cfg, so link it with all seq points starting bbs.
+ */
+ l = g_slist_last (bb->seq_points);
+ if (l) {
+ endfinally_seq_point = l->data;
+
+ for (bb2 = cfg->bb_entry; bb2; bb2 = bb2->next_bb) {
+ GSList *l = g_slist_last (bb2->seq_points);
+
+ if (l) {
+ MonoInst *ins = l->data;
+
+ if (!(ins->inst_imm == METHOD_ENTRY_IL_OFFSET || ins->inst_imm == METHOD_EXIT_IL_OFFSET) && ins != endfinally_seq_point)
+ next [endfinally_seq_point->backend.size] = g_slist_append (next [endfinally_seq_point->backend.size], GUINT_TO_POINTER (ins->backend.size));
+ }
+ }
+ }
+ }
+ }
+
+ if (cfg->verbose_level > 2) {
+ printf ("\nSEQ POINT MAP: \n");
+ }
+
+ for (i = 0; i < cfg->seq_points->len; ++i) {
+ SeqPoint *sp = &info->seq_points [i];
+ GSList *l;
+ int j, next_index;
+
+ sp->next_len = g_slist_length (next [i]);
+ sp->next = g_new (int, sp->next_len);
+ j = 0;
+ if (cfg->verbose_level > 2 && next [i]) {
+ printf ("\tIL0x%x ->", sp->il_offset);
+ for (l = next [i]; l; l = l->next) {
+ next_index = GPOINTER_TO_UINT (l->data);
+ printf (" IL0x%x", info->seq_points [next_index].il_offset);
+ }
+ printf ("\n");
+ }
+ for (l = next [i]; l; l = l->next) {
+ next_index = GPOINTER_TO_UINT (l->data);
+ sp->next [j ++] = next_index;
+ }
+ g_slist_free (next [i]);
+ }
+ g_free (next);
+
+ cfg->seq_point_info = info;
+
+ // FIXME: dynamic methods
+ if (!cfg->compile_aot) {
+ mono_domain_lock (domain);
+ // FIXME: How can the lookup succeed ?
+ if (!g_hash_table_lookup (domain_jit_info (domain)->seq_points, cfg->method_to_register))
+ 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;
+}
+
+MonoSeqPointInfo*
+get_seq_points (MonoDomain *domain, MonoMethod *method)
+{
+ MonoSeqPointInfo *seq_points;
+
+ mono_domain_lock (domain);
+ seq_points = g_hash_table_lookup (domain_jit_info (domain)->seq_points, method);
+ if (!seq_points && method->is_inflated) {
+ /* generic sharing + aot */
+ seq_points = g_hash_table_lookup (domain_jit_info (domain)->seq_points, mono_method_get_declaring_generic_method (method));
+ if (!seq_points)
+ seq_points = g_hash_table_lookup (domain_jit_info (domain)->seq_points, mini_get_shared_method (method));
+ }
+ mono_domain_unlock (domain);
+
+ return seq_points;
+}
+
+/*
+ * find_next_seq_point_for_native_offset:
+ *
+ * Find the first sequence point after NATIVE_OFFSET.
+ */
+SeqPoint*
+find_next_seq_point_for_native_offset (MonoDomain *domain, MonoMethod *method, gint32 native_offset, MonoSeqPointInfo **info)
+{
+ MonoSeqPointInfo *seq_points;
+ int i;
+
+ seq_points = get_seq_points (domain, method);
+ if (!seq_points) {
+ if (info)
+ *info = NULL;
+ return NULL;
+ }
+ g_assert (seq_points);
+ if (info)
+ *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_prev_seq_point_for_native_offset:
+ *
+ * Find the first sequence point before NATIVE_OFFSET.
+ */
+SeqPoint*
+find_prev_seq_point_for_native_offset (MonoDomain *domain, MonoMethod *method, gint32 native_offset, MonoSeqPointInfo **info)
+{
+ MonoSeqPointInfo *seq_points;
+ int i;
+
+ seq_points = get_seq_points (domain, method);
+ if (info)
+ *info = seq_points;
+ if (!seq_points)
+ return NULL;
+
+ for (i = seq_points->len - 1; i >= 0; --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.
+ */
+G_GNUC_UNUSED SeqPoint*
+find_seq_point (MonoDomain *domain, MonoMethod *method, gint32 il_offset, MonoSeqPointInfo **info)
+{
+ MonoSeqPointInfo *seq_points;
+ int i;
+
+ *info = NULL;
+
+ seq_points = get_seq_points (domain, method);
+ if (!seq_points)
+ return NULL;
+ *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;
+}
\ No newline at end of file
--- /dev/null
+/*
+ * Copyright 2014 Xamarin Inc
+ */
+
+#ifndef __MONO_SEQ_POINTS_H__
+#define __MONO_SEQ_POINTS_H__
+
+#define MONO_SEQ_POINT_FLAG_NONEMPTY_STACK 1
+
+/* IL offsets used to mark the sequence points belonging to method entry/exit events */
+#define METHOD_ENTRY_IL_OFFSET -1
+#define METHOD_EXIT_IL_OFFSET 0xffffff
+
+/* Native offset used to mark seq points in dead code */
+#define SEQ_POINT_NATIVE_OFFSET_DEAD_CODE -1
+
+typedef struct {
+ int il_offset, native_offset, flags;
+ /* Indexes of successor sequence points */
+ int *next;
+ /* Number of entries in next */
+ int next_len;
+} SeqPoint;
+
+typedef struct MonoSeqPointInfo {
+ int len;
+ SeqPoint seq_points [MONO_ZERO_LEN_ARRAY];
+} MonoSeqPointInfo;
+
+void
+mono_save_seq_point_info (MonoCompile *cfg);
+
+MonoSeqPointInfo*
+get_seq_points (MonoDomain *domain, MonoMethod *method);
+
+SeqPoint*
+find_next_seq_point_for_native_offset (MonoDomain *domain, MonoMethod *method, gint32 native_offset, MonoSeqPointInfo **info);
+
+SeqPoint*
+find_prev_seq_point_for_native_offset (MonoDomain *domain, MonoMethod *method, gint32 native_offset, MonoSeqPointInfo **info);
+
+G_GNUC_UNUSED SeqPoint*
+find_seq_point (MonoDomain *domain, MonoMethod *method, gint32 il_offset, MonoSeqPointInfo **info);
+
+#endif /* __MONO_SEQ_POINTS_H__ */
\ No newline at end of file