2 * seq-points.c: Sequence Points functions
5 * Marcos Henrich (marcos.henrich@xamarin.com)
7 * Copyright 2014 Xamarin, Inc (http://www.xamarin.com)
11 #include "seq-points.h"
14 encode_var_int (guint8* buf, int val)
19 guint8 byte = val & 0x7f;
20 g_assert (size < 4 && "value has more than 28 bits");
31 decode_var_int (guint8* buf, int* val)
37 b = *(p++); low = (b & 0x7f) ; if(!(b & 0x80)) goto done;
38 b = *(p++); low |= (b & 0x7f) << 7; if(!(b & 0x80)) goto done;
39 b = *(p++); low |= (b & 0x7f) << 14; if(!(b & 0x80)) goto done;
40 b = *(p++); low |= (b & 0x7f) << 21; if(!(b & 0x80)) goto done;
42 g_assert (FALSE && "value has more than 28 bits");
51 encode_zig_zag (int val)
53 return (val << 1) ^ (val >> 31);
57 decode_zig_zag (guint32 val)
60 return (n >> 1) ^ (-(n & 1));
64 allocated_seq_point_size_add (MonoSeqPointInfo *info)
66 int size = sizeof (MonoSeqPointInfo) + sizeof (GByteArray) + info->array->len;
68 mono_jit_stats.allocated_seq_points_size += size;
72 seq_point_read (SeqPoint* seq_point, guint8* ptr, guint8* buffer_ptr, gboolean has_debug_data)
77 ptr += decode_var_int (ptr, &value);
78 seq_point->il_offset += decode_zig_zag (value);
80 ptr += decode_var_int (ptr, &value);
81 seq_point->native_offset += decode_zig_zag (value);
84 ptr += decode_var_int (ptr, &value);
85 seq_point->flags = value;
87 ptr += decode_var_int (ptr, &value);
88 seq_point->next_len = value;
90 if (seq_point->next_len) {
91 // store next offset and skip it
92 seq_point->next_offset = ptr - buffer_ptr;
93 ptr += seq_point->next_len;
100 static MonoSeqPointInfo*
101 seq_point_info_new (gboolean alloc_arrays, gboolean has_debug_data)
103 MonoSeqPointInfo* info = g_new0 (MonoSeqPointInfo, 1);
104 info->alloc_arrays = alloc_arrays;
105 info->has_debug_data = has_debug_data;
107 info->array = g_byte_array_new ();
109 info->array = g_new0 (GByteArray, 1);
115 seq_point_info_free (gpointer ptr)
117 MonoSeqPointInfo* info = (MonoSeqPointInfo*) ptr;
119 if (info->alloc_arrays) {
120 g_byte_array_free (info->array, TRUE);
122 g_free (info->array);
128 seq_point_info_add_seq_point (MonoSeqPointInfo *info, SeqPoint *sp, SeqPoint *last_seq_point, GSList *next)
130 int il_delta, native_delta;
135 if (!info->has_debug_data &&
136 (sp->il_offset == METHOD_ENTRY_IL_OFFSET || sp->il_offset == METHOD_EXIT_IL_OFFSET))
139 /* check that data can be added to the arrays */
140 g_assert (info->alloc_arrays);
142 il_delta = sp->il_offset - last_seq_point->il_offset;
143 native_delta = sp->native_offset - last_seq_point->native_offset;
145 len = encode_var_int (buffer, encode_zig_zag (il_delta));
146 g_byte_array_append (info->array, buffer, len);
148 len = encode_var_int (buffer, encode_zig_zag (native_delta));
149 g_byte_array_append (info->array, buffer, len);
151 if (info->has_debug_data) {
152 sp->next_offset = info->array->len;
153 sp->next_len = g_slist_length (next);
155 len = encode_var_int (buffer, sp->flags);
156 g_byte_array_append (info->array, buffer, len);
158 len = encode_var_int (buffer, sp->next_len);
159 g_byte_array_append (info->array, buffer, len);
161 for (l = next; l; l = l->next) {
162 int next_index = GPOINTER_TO_UINT (l->data);
164 int len = encode_var_int (buffer, next_index);
165 g_byte_array_append (info->array, buffer, len);
173 collect_pred_seq_points (MonoBasicBlock *bb, MonoInst *ins, GSList **next, int depth)
176 MonoBasicBlock *in_bb;
179 for (i = 0; i < bb->in_count; ++i) {
180 in_bb = bb->in_bb [i];
182 if (in_bb->last_seq_point) {
183 int src_index = in_bb->last_seq_point->backend.size;
184 int dst_index = ins->backend.size;
186 /* bb->in_bb might contain duplicates */
187 for (l = next [src_index]; l; l = l->next)
188 if (GPOINTER_TO_UINT (l->data) == dst_index)
191 next [src_index] = g_slist_append (next [src_index], GUINT_TO_POINTER (dst_index));
193 /* Have to look at its predecessors */
195 collect_pred_seq_points (in_bb, ins, next, depth + 1);
201 mono_save_seq_point_info (MonoCompile *cfg)
204 GSList *bb_seq_points, *l;
206 MonoDomain *domain = cfg->domain;
209 SeqPoint* seq_points;
210 gboolean has_debug_data = cfg->gen_seq_points_debug_data;
212 if (!cfg->seq_points)
215 seq_points = g_new0 (SeqPoint, cfg->seq_points->len);
217 for (i = 0; i < cfg->seq_points->len; ++i) {
218 SeqPoint *sp = &seq_points [i];
219 MonoInst *ins = g_ptr_array_index (cfg->seq_points, i);
221 sp->il_offset = ins->inst_imm;
222 sp->native_offset = ins->inst_offset;
223 if (ins->flags & MONO_INST_NONEMPTY_STACK)
224 sp->flags |= MONO_SEQ_POINT_FLAG_NONEMPTY_STACK;
227 ins->backend.size = i;
230 if (has_debug_data) {
232 * For each sequence point, compute the list of sequence points immediately
233 * following it, this is needed to implement 'step over' in the debugger agent.
235 next = g_new0 (GSList*, cfg->seq_points->len);
236 for (bb = cfg->bb_entry; bb; bb = bb->next_bb) {
237 bb_seq_points = g_slist_reverse (bb->seq_points);
239 for (l = bb_seq_points; l; l = l->next) {
240 MonoInst *ins = l->data;
242 if (ins->inst_imm == METHOD_ENTRY_IL_OFFSET || ins->inst_imm == METHOD_EXIT_IL_OFFSET)
243 /* Used to implement method entry/exit events */
245 if (ins->inst_offset == SEQ_POINT_NATIVE_OFFSET_DEAD_CODE)
249 /* Link with the previous seq point in the same bb */
250 next [last->backend.size] = g_slist_append (next [last->backend.size], GUINT_TO_POINTER (ins->backend.size));
252 /* Link with the last bb in the previous bblocks */
253 collect_pred_seq_points (bb, ins, next, 0);
259 if (bb->last_ins && bb->last_ins->opcode == OP_ENDFINALLY && bb->seq_points) {
261 MonoInst *endfinally_seq_point = NULL;
264 * The ENDFINALLY branches are not represented in the cfg, so link it with all seq points starting bbs.
266 l = g_slist_last (bb->seq_points);
268 endfinally_seq_point = l->data;
270 for (bb2 = cfg->bb_entry; bb2; bb2 = bb2->next_bb) {
271 GSList *l = g_slist_last (bb2->seq_points);
274 MonoInst *ins = l->data;
276 if (!(ins->inst_imm == METHOD_ENTRY_IL_OFFSET || ins->inst_imm == METHOD_EXIT_IL_OFFSET) && ins != endfinally_seq_point)
277 next [endfinally_seq_point->backend.size] = g_slist_append (next [endfinally_seq_point->backend.size], GUINT_TO_POINTER (ins->backend.size));
284 if (cfg->verbose_level > 2) {
285 printf ("\nSEQ POINT MAP: \n");
287 for (i = 0; i < cfg->seq_points->len; ++i) {
288 SeqPoint *sp = &seq_points [i];
294 printf ("\tIL0x%x ->", sp->il_offset);
295 for (l = next [i]; l; l = l->next) {
296 int next_index = GPOINTER_TO_UINT (l->data);
297 printf (" IL0x%x", seq_points [next_index].il_offset);
304 cfg->seq_point_info = seq_point_info_new (TRUE, has_debug_data);
306 { /* Add sequence points to seq_point_info */
307 SeqPoint zero_seq_point = {0};
308 SeqPoint* last_seq_point = &zero_seq_point;
310 for (i = 0; i < cfg->seq_points->len; ++i) {
311 SeqPoint *sp = &seq_points [i];
312 GSList* next_list = NULL;
317 if (seq_point_info_add_seq_point (cfg->seq_point_info, sp, last_seq_point, next_list))
321 g_slist_free (next [i]);
328 allocated_seq_point_size_add (cfg->seq_point_info);
330 // FIXME: dynamic methods
331 if (!cfg->compile_aot) {
332 mono_domain_lock (domain);
333 // FIXME: How can the lookup succeed ?
334 if (!g_hash_table_lookup (domain_jit_info (domain)->seq_points, cfg->method_to_register))
335 g_hash_table_insert (domain_jit_info (domain)->seq_points, cfg->method_to_register, cfg->seq_point_info);
336 mono_domain_unlock (domain);
339 g_ptr_array_free (cfg->seq_points, TRUE);
340 cfg->seq_points = NULL;
344 get_seq_points (MonoDomain *domain, MonoMethod *method)
346 MonoSeqPointInfo *seq_points;
348 mono_domain_lock (domain);
349 seq_points = g_hash_table_lookup (domain_jit_info (domain)->seq_points, method);
350 if (!seq_points && method->is_inflated) {
351 /* generic sharing + aot */
352 seq_points = g_hash_table_lookup (domain_jit_info (domain)->seq_points, mono_method_get_declaring_generic_method (method));
354 seq_points = g_hash_table_lookup (domain_jit_info (domain)->seq_points, mini_get_shared_method (method));
356 mono_domain_unlock (domain);
362 seq_point_find_next_by_native_offset (MonoSeqPointInfo* info, int native_offset, SeqPoint* seq_point)
365 seq_point_iterator_init (&it, info);
366 while (seq_point_iterator_next (&it)) {
367 if (it.seq_point.native_offset >= native_offset) {
368 memcpy (seq_point, &it.seq_point, sizeof (SeqPoint));
377 seq_point_find_prev_by_native_offset (MonoSeqPointInfo* info, int native_offset, SeqPoint* seq_point)
379 SeqPoint prev_seq_point;
380 gboolean is_first = TRUE;
382 seq_point_iterator_init (&it, info);
383 while (seq_point_iterator_next (&it) && it.seq_point.native_offset <= native_offset) {
384 memcpy (&prev_seq_point, &it.seq_point, sizeof (SeqPoint));
388 if (!is_first && prev_seq_point.native_offset <= native_offset) {
389 memcpy (seq_point, &prev_seq_point, sizeof (SeqPoint));
397 seq_point_find_by_il_offset (MonoSeqPointInfo* info, int il_offset, SeqPoint* seq_point)
400 seq_point_iterator_init (&it, info);
401 while (seq_point_iterator_next (&it)) {
402 if (it.seq_point.il_offset == il_offset) {
403 memcpy (seq_point, &it.seq_point, sizeof (SeqPoint));
412 * find_next_seq_point_for_native_offset:
414 * Find the first sequence point after NATIVE_OFFSET.
417 find_next_seq_point_for_native_offset (MonoDomain *domain, MonoMethod *method, gint32 native_offset, MonoSeqPointInfo **info, SeqPoint* seq_point)
419 MonoSeqPointInfo *seq_points;
421 seq_points = get_seq_points (domain, method);
430 return seq_point_find_next_by_native_offset (seq_points, native_offset, seq_point);
434 * find_prev_seq_point_for_native_offset:
436 * Find the first sequence point before NATIVE_OFFSET.
439 find_prev_seq_point_for_native_offset (MonoDomain *domain, MonoMethod *method, gint32 native_offset, MonoSeqPointInfo **info, SeqPoint* seq_point)
441 MonoSeqPointInfo *seq_points;
443 seq_points = get_seq_points (domain, method);
452 return seq_point_find_prev_by_native_offset (seq_points, native_offset, seq_point);
458 * Find the sequence point corresponding to the IL offset IL_OFFSET, which
459 * should be the location of a sequence point.
462 find_seq_point (MonoDomain *domain, MonoMethod *method, gint32 il_offset, MonoSeqPointInfo **info, SeqPoint *seq_point)
464 MonoSeqPointInfo *seq_points;
466 seq_points = get_seq_points (domain, method);
475 return seq_point_find_by_il_offset (seq_points, il_offset, seq_point);
479 seq_point_init_next (MonoSeqPointInfo* info, SeqPoint sp, SeqPoint* next)
484 GArray* seq_points = g_array_new (FALSE, TRUE, sizeof (SeqPoint));
486 g_assert (info->has_debug_data);
488 seq_point_iterator_init (&it, info);
489 while (seq_point_iterator_next (&it))
490 g_array_append_vals (seq_points, &it.seq_point, 1);
492 ptr = info->array->data + sp.next_offset;
493 for (i = 0; i < sp.next_len; i++) {
495 ptr += decode_var_int (ptr, &next_index);
496 g_assert (next_index < seq_points->len);
497 memcpy (&next[i], seq_points->data + next_index * sizeof (SeqPoint), sizeof (SeqPoint));
500 g_array_free (seq_points, TRUE);
504 seq_point_iterator_next (SeqPointIterator* it)
506 if (it->ptr >= it->info->array->data + it->info->array->len)
509 it->ptr += seq_point_read (&it->seq_point, it->ptr, it->info->array->data, it->info->has_debug_data);
515 seq_point_iterator_init (SeqPointIterator* it, MonoSeqPointInfo* info)
518 it->ptr = it->info->array->data;
519 memset(&it->seq_point, 0, sizeof(SeqPoint));
523 seq_point_info_write (MonoSeqPointInfo* info, guint8* buffer)
525 guint8* buffer0 = buffer;
527 memcpy (buffer, &info->has_debug_data, 1);
530 //Write sequence points
531 buffer += encode_var_int (buffer, info->array->len);
532 memcpy (buffer, info->array->data, info->array->len);
533 buffer += info->array->len;
535 return buffer - buffer0;
539 seq_point_info_read (MonoSeqPointInfo** info, guint8* buffer, gboolean copy)
541 guint8* buffer0 = buffer;
543 gboolean has_debug_data;
545 memcpy (&has_debug_data, buffer, 1);
548 (*info) = seq_point_info_new (copy, has_debug_data);
550 buffer += decode_var_int (buffer, &size);
552 g_byte_array_append ((*info)->array, buffer, size);
554 (*info)->array->data = buffer;
555 (*info)->array->len = size;
559 return buffer - buffer0;
563 * Returns the maximum size of mono_seq_point_info_write.
566 seq_point_info_write_size (MonoSeqPointInfo* info)
568 //8 is the maximum size required to store the size of the arrays.
569 //1 is the byte used to store has_debug_data.
570 int size = 8 + 1 + info->array->len;