Merge pull request #2524 from lambdageek/monoerror-mono_string_new_utf16_checked
[mono.git] / mono / mini / seq-points.c
1 /*
2  * seq-points.c: Sequence Points functions
3  *
4  * Authors:
5  *   Marcos Henrich (marcos.henrich@xamarin.com)
6  *
7  * Copyright 2014 Xamarin, Inc (http://www.xamarin.com)
8  */
9
10 #include "mini.h"
11 #include "seq-points.h"
12
13 static void
14 collect_pred_seq_points (MonoBasicBlock *bb, MonoInst *ins, GSList **next, int depth)
15 {
16         int i;
17         MonoBasicBlock *in_bb;
18         GSList *l;
19
20         for (i = 0; i < bb->in_count; ++i) {
21                 in_bb = bb->in_bb [i];
22
23                 if (in_bb->last_seq_point) {
24                         int src_index = in_bb->last_seq_point->backend.size;
25                         int dst_index = ins->backend.size;
26
27                         /* bb->in_bb might contain duplicates */
28                         for (l = next [src_index]; l; l = l->next)
29                                 if (GPOINTER_TO_UINT (l->data) == dst_index)
30                                         break;
31                         if (!l)
32                                 next [src_index] = g_slist_append (next [src_index], GUINT_TO_POINTER (dst_index));
33                 } else {
34                         /* Have to look at its predecessors */
35                         if (depth < 5)
36                                 collect_pred_seq_points (in_bb, ins, next, depth + 1);
37                 }
38         }
39 }
40
41 void
42 mono_save_seq_point_info (MonoCompile *cfg)
43 {
44         MonoBasicBlock *bb;
45         GSList *bb_seq_points, *l;
46         MonoInst *last;
47         MonoDomain *domain = cfg->domain;
48         int i, seq_info_size;
49         GSList **next = NULL;
50         SeqPoint* seq_points;
51         GByteArray* array;
52         gboolean has_debug_data = cfg->gen_sdb_seq_points;
53
54         if (!cfg->seq_points)
55                 return;
56
57         seq_points = g_new0 (SeqPoint, cfg->seq_points->len);
58
59         for (i = 0; i < cfg->seq_points->len; ++i) {
60                 SeqPoint *sp = &seq_points [i];
61                 MonoInst *ins = (MonoInst *)g_ptr_array_index (cfg->seq_points, i);
62
63                 sp->il_offset = ins->inst_imm;
64                 sp->native_offset = ins->inst_offset;
65                 if (ins->flags & MONO_INST_NONEMPTY_STACK)
66                         sp->flags |= MONO_SEQ_POINT_FLAG_NONEMPTY_STACK;
67
68                 /* Used below */
69                 ins->backend.size = i;
70         }
71
72         if (has_debug_data) {
73                 /*
74                  * For each sequence point, compute the list of sequence points immediately
75                  * following it, this is needed to implement 'step over' in the debugger agent.
76                  */
77                 next = g_new0 (GSList*, cfg->seq_points->len);
78                 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
79                         bb_seq_points = g_slist_reverse (bb->seq_points);
80                         last = NULL;
81                         for (l = bb_seq_points; l; l = l->next) {
82                                 MonoInst *ins = (MonoInst *)l->data;
83
84                                 if (ins->inst_imm == METHOD_ENTRY_IL_OFFSET || ins->inst_imm == METHOD_EXIT_IL_OFFSET)
85                                 /* Used to implement method entry/exit events */
86                                         continue;
87                                 if (ins->inst_offset == SEQ_POINT_NATIVE_OFFSET_DEAD_CODE)
88                                         continue;
89
90                                 if (last != NULL) {
91                                         /* Link with the previous seq point in the same bb */
92                                         next [last->backend.size] = g_slist_append (next [last->backend.size], GUINT_TO_POINTER (ins->backend.size));
93                                 } else {
94                                         /* Link with the last bb in the previous bblocks */
95                                         collect_pred_seq_points (bb, ins, next, 0);
96                                 }
97
98                                 last = ins;
99                         }
100
101                         /* The second case handles endfinally opcodes which are in a separate bb by themselves */
102                         if ((bb->last_ins && bb->last_ins->opcode == OP_ENDFINALLY && bb->seq_points) || (bb->out_count == 1 && bb->out_bb [0]->code && bb->out_bb [0]->code->opcode == OP_ENDFINALLY)) {
103                                 MonoBasicBlock *bb2;
104                                 MonoInst *endfinally_seq_point = NULL;
105
106                                 /*
107                                  * The ENDFINALLY branches are not represented in the cfg, so link it with all seq points starting bbs.
108                                  */
109                                 l = g_slist_last (bb->seq_points);
110                                 if (l) {
111                                         endfinally_seq_point = (MonoInst *)l->data;
112
113                                         for (bb2 = cfg->bb_entry; bb2; bb2 = bb2->next_bb) {
114                                                 GSList *l = g_slist_last (bb2->seq_points);
115
116                                                 if (l) {
117                                                         MonoInst *ins = (MonoInst *)l->data;
118
119                                                         if (!(ins->inst_imm == METHOD_ENTRY_IL_OFFSET || ins->inst_imm == METHOD_EXIT_IL_OFFSET) && ins != endfinally_seq_point)
120                                                                 next [endfinally_seq_point->backend.size] = g_slist_append (next [endfinally_seq_point->backend.size], GUINT_TO_POINTER (ins->backend.size));
121                                                 }
122                                         }
123                                 }
124                         }
125                 }
126
127                 if (cfg->verbose_level > 2) {
128                         printf ("\nSEQ POINT MAP: \n");
129
130                         for (i = 0; i < cfg->seq_points->len; ++i) {
131                                 SeqPoint *sp = &seq_points [i];
132                                 GSList *l;
133
134                                 if (!next [i])
135                                         continue;
136
137                                 printf ("\tIL0x%x[0x%0x] ->", sp->il_offset, sp->native_offset);
138                                 for (l = next [i]; l; l = l->next) {
139                                         int next_index = GPOINTER_TO_UINT (l->data);
140                                         printf (" IL0x%x", seq_points [next_index].il_offset);
141                                 }
142                                 printf ("\n");
143                         }
144                 }
145         }
146
147         array = g_byte_array_new ();
148
149         { /* Add sequence points to seq_point_info */
150                 SeqPoint zero_seq_point = {0};
151                 SeqPoint* last_seq_point = &zero_seq_point;
152
153                 for (i = 0; i < cfg->seq_points->len; ++i) {
154                         SeqPoint *sp = &seq_points [i];
155                         GSList* next_list = NULL;
156
157                         if (has_debug_data)
158                                 next_list = next[i];
159
160                         if (mono_seq_point_info_add_seq_point (array, sp, last_seq_point, next_list, has_debug_data))
161                                 last_seq_point = sp;
162
163                         if (has_debug_data)
164                                 g_slist_free (next [i]);
165                 }
166         }
167
168         if (has_debug_data)
169                 g_free (next);
170
171         cfg->seq_point_info = mono_seq_point_info_new (array->len, TRUE, array->data, has_debug_data, &seq_info_size);
172         mono_jit_stats.allocated_seq_points_size += seq_info_size;
173
174         g_byte_array_free (array, TRUE);
175
176         // FIXME: dynamic methods
177         if (!cfg->compile_aot) {
178                 mono_domain_lock (domain);
179                 // FIXME: How can the lookup succeed ?
180                 if (!g_hash_table_lookup (domain_jit_info (domain)->seq_points, cfg->method_to_register))
181                         g_hash_table_insert (domain_jit_info (domain)->seq_points, cfg->method_to_register, cfg->seq_point_info);
182                 mono_domain_unlock (domain);
183         }
184
185         g_ptr_array_free (cfg->seq_points, TRUE);
186         cfg->seq_points = NULL;
187 }
188
189 MonoSeqPointInfo*
190 mono_get_seq_points (MonoDomain *domain, MonoMethod *method)
191 {
192         MonoSeqPointInfo *seq_points;
193         MonoMethod *declaring_generic_method = NULL, *shared_method = NULL;
194
195         if (method->is_inflated) {
196                 declaring_generic_method = mono_method_get_declaring_generic_method (method);
197                 shared_method = mini_get_shared_method (method);
198         }
199
200         mono_loader_lock ();
201         seq_points = (MonoSeqPointInfo *)g_hash_table_lookup (domain_jit_info (domain)->seq_points, method);
202         if (!seq_points && method->is_inflated) {
203                 /* generic sharing + aot */
204                 seq_points = (MonoSeqPointInfo *)g_hash_table_lookup (domain_jit_info (domain)->seq_points, declaring_generic_method);
205                 if (!seq_points)
206                         seq_points = (MonoSeqPointInfo *)g_hash_table_lookup (domain_jit_info (domain)->seq_points, shared_method);
207         }
208         mono_loader_unlock ();
209
210         return seq_points;
211 }
212
213 /*
214  * mono_find_next_seq_point_for_native_offset:
215  *
216  *   Find the first sequence point after NATIVE_OFFSET.
217  */
218 gboolean
219 mono_find_next_seq_point_for_native_offset (MonoDomain *domain, MonoMethod *method, gint32 native_offset, MonoSeqPointInfo **info, SeqPoint* seq_point)
220 {
221         MonoSeqPointInfo *seq_points;
222
223         seq_points = mono_get_seq_points (domain, method);
224         if (!seq_points) {
225                 if (info)
226                         *info = NULL;
227                 return FALSE;
228         }
229         if (info)
230                 *info = seq_points;
231
232         return mono_seq_point_find_next_by_native_offset (seq_points, native_offset, seq_point);
233 }
234
235 /*
236  * mono_find_prev_seq_point_for_native_offset:
237  *
238  *   Find the first sequence point before NATIVE_OFFSET.
239  */
240 gboolean
241 mono_find_prev_seq_point_for_native_offset (MonoDomain *domain, MonoMethod *method, gint32 native_offset, MonoSeqPointInfo **info, SeqPoint* seq_point)
242 {
243         MonoSeqPointInfo *seq_points;
244
245         seq_points = mono_get_seq_points (domain, method);
246         if (!seq_points) {
247                 if (info)
248                         *info = NULL;
249                 return FALSE;
250         }
251         if (info)
252                 *info = seq_points;
253
254         return mono_seq_point_find_prev_by_native_offset (seq_points, native_offset, seq_point);
255 }
256
257 /*
258  * mono_find_seq_point:
259  *
260  *   Find the sequence point corresponding to the IL offset IL_OFFSET, which
261  * should be the location of a sequence point.
262  */
263 gboolean
264 mono_find_seq_point (MonoDomain *domain, MonoMethod *method, gint32 il_offset, MonoSeqPointInfo **info, SeqPoint *seq_point)
265 {
266         MonoSeqPointInfo *seq_points;
267
268         seq_points = mono_get_seq_points (domain, method);
269         if (!seq_points) {
270                 if (info)
271                         *info = NULL;
272                 return FALSE;
273         }
274         if (info)
275                 *info = seq_points;
276
277         return mono_seq_point_find_by_il_offset (seq_points, il_offset, seq_point);
278 }
279
280 void
281 mono_bb_deduplicate_op_il_seq_points (MonoCompile *cfg, MonoBasicBlock *bb)
282 {
283         MonoInst *ins, *n, *prev;
284
285         MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
286                 if (ins->opcode != OP_IL_SEQ_POINT)
287                         continue;
288
289                 prev = mono_inst_prev (ins, FILTER_NOP);
290
291                 if (!prev || ins == prev || prev->opcode != OP_IL_SEQ_POINT)
292                         continue;
293
294                 MONO_REMOVE_INS (bb, prev);
295         };
296 }
297
298 void
299 mono_image_get_aot_seq_point_path (MonoImage *image, char **str)
300 {
301         int size = strlen (image->name) + strlen (SEQ_POINT_AOT_EXT) + 1;
302         *str = (char *)g_malloc (size);
303         g_sprintf (*str, "%s%s", image->name, SEQ_POINT_AOT_EXT);
304 }