Merge pull request #2338 from BogdanovKirill/httpwritefix3
[mono.git] / mono / mini / seq-points.c
index b5dad536646d5b34f50f4d30d111ed217313562e..ac22ca41f070d0201b7c4b55371cc597b1e97a51 100644 (file)
 #include "mini.h"
 #include "seq-points.h"
 
-typedef struct {
-       guint8 *data;
-       int len;
-       /* When has_debug_data is set to false only il and native deltas are saved */
-       gboolean has_debug_data;
-       /* When alloc_data is set to true data allocation/deallocation is managed by this structure */
-       gboolean alloc_data;
-} SeqPointInfoInflated;
-
-static int
-encode_var_int (guint8 *buf, guint8 **out_buf, int val)
-{
-       guint8 size = 0;
-
-       do {
-               guint8 byte = val & 0x7f;
-               g_assert (size < 4 && "value has more than 28 bits");
-               val >>= 7;
-               if(val) byte |= 0x80;
-               *(buf++) = byte;
-               size++;
-       } while (val);
-
-       if (out_buf)
-               *out_buf = buf;
-
-       return size;
-}
-
-static int
-decode_var_int (guint8* buf, guint8 **out_buf)
-{
-       guint8* p = buf;
-
-       int low;
-       int b;
-       b = *(p++); low   = (b & 0x7f)      ; if(!(b & 0x80)) goto done;
-       b = *(p++); low  |= (b & 0x7f) <<  7; if(!(b & 0x80)) goto done;
-       b = *(p++); low  |= (b & 0x7f) << 14; if(!(b & 0x80)) goto done;
-       b = *(p++); low  |= (b & 0x7f) << 21; if(!(b & 0x80)) goto done;
-
-       g_assert (FALSE && "value has more than 28 bits");
-
-done:
-
-       if (out_buf)
-               *out_buf = p;
-
-       return low;
-}
-
-static guint32
-encode_zig_zag (int val)
-{
-       return (val << 1) ^ (val >> 31);
-}
-
-static int
-decode_zig_zag (guint32 val)
-{
-       int n = val;
-       return (n >> 1) ^ (-(n & 1));
-}
-
-static SeqPointInfoInflated
-seq_point_info_inflate (MonoSeqPointInfo *info)
-{
-       SeqPointInfoInflated info_inflated;
-       guint8 *ptr = (guint8*) info;
-       int value;
-
-       value = decode_var_int (ptr, &ptr);
-
-       info_inflated.len = value >> 2;
-       info_inflated.has_debug_data = (value & 1) != 0;
-       info_inflated.alloc_data = (value & 2) != 0;
-
-       if (info_inflated.alloc_data)
-               info_inflated.data = ptr;
-       else
-               memcpy (&info_inflated.data, ptr, sizeof (guint8*));
-
-       return info_inflated;
-}
-
-static MonoSeqPointInfo*
-seq_point_info_new (int len, gboolean alloc_data, guint8 *data, gboolean has_debug_data)
-{
-       MonoSeqPointInfo *info;
-       guint8 *info_ptr;
-       guint8 buffer[4];
-       int buffer_len;
-       int value;
-       int data_size;
-
-       value = len << 2;
-       if (has_debug_data)
-               value |= 1;
-       if (alloc_data)
-               value |= 2;
-
-       buffer_len = encode_var_int (buffer, NULL, value);
-
-       data_size = buffer_len + (alloc_data? len : sizeof (guint8*));
-       info_ptr = g_new0 (guint8, data_size);
-       info = (MonoSeqPointInfo*) info_ptr;
-
-       memcpy (info_ptr, buffer, buffer_len);
-       info_ptr += buffer_len;
-
-       if (alloc_data)
-               memcpy (info_ptr, data, len);
-       else
-               memcpy (info_ptr, &data, sizeof (guint8*));
-
-       mono_jit_stats.allocated_seq_points_size += data_size;
-
-       return info;
-}
-
-void
-seq_point_info_free (gpointer ptr)
-{
-       MonoSeqPointInfo* info = (MonoSeqPointInfo*) ptr;
-       g_free (info);
-}
-
-static int
-seq_point_read (SeqPoint* seq_point, guint8* ptr, guint8* buffer_ptr, gboolean has_debug_data)
-{
-       int value, i;
-       guint8* ptr0 = ptr;
-
-       value = decode_var_int (ptr, &ptr);
-       seq_point->il_offset += decode_zig_zag (value);
-
-       value = decode_var_int (ptr, &ptr);
-       seq_point->native_offset += decode_zig_zag (value);
-
-       if (has_debug_data) {
-               value = decode_var_int (ptr, &ptr);
-               seq_point->flags = value;
-
-               if (seq_point->flags & MONO_SEQ_POINT_FLAG_EXIT_IL)
-                       seq_point->il_offset = METHOD_EXIT_IL_OFFSET;
-
-               value = decode_var_int (ptr, &ptr);
-               seq_point->next_len = value;
-
-               if (seq_point->next_len) {
-                       // store next offset and skip it
-                       seq_point->next_offset = ptr - buffer_ptr;
-                       for (i = 0; i < seq_point->next_len; ++i)
-                               decode_var_int (ptr, &ptr);
-               }
-       }
-
-       return ptr - ptr0;
-}
-
-static gboolean
-seq_point_info_add_seq_point (GByteArray* array, SeqPoint *sp, SeqPoint *last_seq_point, GSList *next, gboolean has_debug_data)
-{
-       int il_delta, native_delta;
-       GSList *l;
-       guint8 buffer[4];
-       guint8 len;
-       int flags;
-
-       if (!has_debug_data &&
-               (sp->il_offset == METHOD_ENTRY_IL_OFFSET || sp->il_offset == METHOD_EXIT_IL_OFFSET))
-               return FALSE;
-
-       il_delta = sp->il_offset - last_seq_point->il_offset;
-       native_delta = sp->native_offset - last_seq_point->native_offset;
-
-       flags = sp->flags;
-
-       if (has_debug_data && sp->il_offset == METHOD_EXIT_IL_OFFSET) {
-               il_delta = 0;
-               flags |= MONO_SEQ_POINT_FLAG_EXIT_IL;
-       }
-
-       len = encode_var_int (buffer, NULL, encode_zig_zag (il_delta));
-       g_byte_array_append (array, buffer, len);
-
-       len = encode_var_int (buffer, NULL, encode_zig_zag (native_delta));
-       g_byte_array_append (array, buffer, len);
-
-       if (has_debug_data) {
-               sp->next_offset = array->len;
-               sp->next_len = g_slist_length (next);
-
-               len = encode_var_int (buffer, NULL, flags);
-               g_byte_array_append (array, buffer, len);
-
-               len = encode_var_int (buffer, NULL, sp->next_len);
-               g_byte_array_append (array, buffer, len);
-
-               for (l = next; l; l = l->next) {
-                       int next_index = GPOINTER_TO_UINT (l->data);
-                       guint8 buffer[4];
-                       int len = encode_var_int (buffer, NULL, next_index);
-                       g_byte_array_append (array, buffer, len);
-               }
-       }
-
-       return TRUE;
-}
-
 static void
 collect_pred_seq_points (MonoBasicBlock *bb, MonoInst *ins, GSList **next, int depth)
 {
@@ -255,11 +45,11 @@ mono_save_seq_point_info (MonoCompile *cfg)
        GSList *bb_seq_points, *l;
        MonoInst *last;
        MonoDomain *domain = cfg->domain;
-       int i;
+       int i, seq_info_size;
        GSList **next = NULL;
        SeqPoint* seq_points;
        GByteArray* array;
-       gboolean has_debug_data = cfg->gen_seq_points_debug_data;
+       gboolean has_debug_data = cfg->gen_sdb_seq_points;
 
        if (!cfg->seq_points)
                return;
@@ -268,7 +58,7 @@ mono_save_seq_point_info (MonoCompile *cfg)
 
        for (i = 0; i < cfg->seq_points->len; ++i) {
                SeqPoint *sp = &seq_points [i];
-               MonoInst *ins = g_ptr_array_index (cfg->seq_points, i);
+               MonoInst *ins = (MonoInst *)g_ptr_array_index (cfg->seq_points, i);
 
                sp->il_offset = ins->inst_imm;
                sp->native_offset = ins->inst_offset;
@@ -289,7 +79,7 @@ mono_save_seq_point_info (MonoCompile *cfg)
                        bb_seq_points = g_slist_reverse (bb->seq_points);
                        last = NULL;
                        for (l = bb_seq_points; l; l = l->next) {
-                               MonoInst *ins = l->data;
+                               MonoInst *ins = (MonoInst *)l->data;
 
                                if (ins->inst_imm == METHOD_ENTRY_IL_OFFSET || ins->inst_imm == METHOD_EXIT_IL_OFFSET)
                                /* Used to implement method entry/exit events */
@@ -308,7 +98,8 @@ mono_save_seq_point_info (MonoCompile *cfg)
                                last = ins;
                        }
 
-                       if (bb->last_ins && bb->last_ins->opcode == OP_ENDFINALLY && bb->seq_points) {
+                       /* The second case handles endfinally opcodes which are in a separate bb by themselves */
+                       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)) {
                                MonoBasicBlock *bb2;
                                MonoInst *endfinally_seq_point = NULL;
 
@@ -317,13 +108,13 @@ mono_save_seq_point_info (MonoCompile *cfg)
                                 */
                                l = g_slist_last (bb->seq_points);
                                if (l) {
-                                       endfinally_seq_point = l->data;
+                                       endfinally_seq_point = (MonoInst *)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;
+                                                       MonoInst *ins = (MonoInst *)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));
@@ -343,7 +134,7 @@ mono_save_seq_point_info (MonoCompile *cfg)
                                if (!next [i])
                                        continue;
 
-                               printf ("\tIL0x%x ->", sp->il_offset);
+                               printf ("\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);
                                        printf (" IL0x%x", seq_points [next_index].il_offset);
@@ -366,7 +157,7 @@ mono_save_seq_point_info (MonoCompile *cfg)
                        if (has_debug_data)
                                next_list = next[i];
 
-                       if (seq_point_info_add_seq_point (array, sp, last_seq_point, next_list, has_debug_data))
+                       if (mono_seq_point_info_add_seq_point (array, sp, last_seq_point, next_list, has_debug_data))
                                last_seq_point = sp;
 
                        if (has_debug_data)
@@ -377,7 +168,8 @@ mono_save_seq_point_info (MonoCompile *cfg)
        if (has_debug_data)
                g_free (next);
 
-       cfg->seq_point_info = seq_point_info_new (array->len, TRUE, array->data, has_debug_data);
+       cfg->seq_point_info = mono_seq_point_info_new (array->len, TRUE, array->data, has_debug_data, &seq_info_size);
+       mono_jit_stats.allocated_seq_points_size += seq_info_size;
 
        g_byte_array_free (array, TRUE);
 
@@ -395,84 +187,40 @@ mono_save_seq_point_info (MonoCompile *cfg)
 }
 
 MonoSeqPointInfo*
-get_seq_points (MonoDomain *domain, MonoMethod *method)
+mono_get_seq_points (MonoDomain *domain, MonoMethod *method)
 {
        MonoSeqPointInfo *seq_points;
+       MonoMethod *declaring_generic_method = NULL, *shared_method = NULL;
+
+       if (method->is_inflated) {
+               declaring_generic_method = mono_method_get_declaring_generic_method (method);
+               shared_method = mini_get_shared_method (method);
+       }
 
-       mono_domain_lock (domain);
-       seq_points = g_hash_table_lookup (domain_jit_info (domain)->seq_points, method);
+       mono_loader_lock ();
+       seq_points = (MonoSeqPointInfo *)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));
+               seq_points = (MonoSeqPointInfo *)g_hash_table_lookup (domain_jit_info (domain)->seq_points, declaring_generic_method);
                if (!seq_points)
-                       seq_points = g_hash_table_lookup (domain_jit_info (domain)->seq_points, mini_get_shared_method (method));
+                       seq_points = (MonoSeqPointInfo *)g_hash_table_lookup (domain_jit_info (domain)->seq_points, shared_method);
        }
-       mono_domain_unlock (domain);
+       mono_loader_unlock ();
 
        return seq_points;
 }
 
-static gboolean
-seq_point_find_next_by_native_offset (MonoSeqPointInfo* info, int native_offset, SeqPoint* seq_point)
-{
-       SeqPointIterator it;
-       seq_point_iterator_init (&it, info);
-       while (seq_point_iterator_next (&it)) {
-               if (it.seq_point.native_offset >= native_offset) {
-                       memcpy (seq_point, &it.seq_point, sizeof (SeqPoint));
-                       return TRUE;
-               }
-       }
-
-       return FALSE;
-}
-
-static gboolean
-seq_point_find_prev_by_native_offset (MonoSeqPointInfo* info, int native_offset, SeqPoint* seq_point)
-{
-       SeqPoint prev_seq_point;
-       gboolean  is_first = TRUE;
-       SeqPointIterator it;
-       seq_point_iterator_init (&it, info);
-       while (seq_point_iterator_next (&it) && it.seq_point.native_offset <= native_offset) {
-               memcpy (&prev_seq_point, &it.seq_point, sizeof (SeqPoint));
-               is_first = FALSE;
-       }
-
-       if (!is_first && prev_seq_point.native_offset <= native_offset) {
-               memcpy (seq_point, &prev_seq_point, sizeof (SeqPoint));
-               return TRUE;
-       }
-
-       return FALSE;
-}
-
-static gboolean
-seq_point_find_by_il_offset (MonoSeqPointInfo* info, int il_offset, SeqPoint* seq_point)
-{
-       SeqPointIterator it;
-       seq_point_iterator_init (&it, info);
-       while (seq_point_iterator_next (&it)) {
-               if (it.seq_point.il_offset == il_offset) {
-                       memcpy (seq_point, &it.seq_point, sizeof (SeqPoint));
-                       return TRUE;
-               }
-       }
-
-       return FALSE;
-}
-
 /*
- * find_next_seq_point_for_native_offset:
+ * mono_find_next_seq_point_for_native_offset:
  *
  *   Find the first sequence point after NATIVE_OFFSET.
  */
 gboolean
-find_next_seq_point_for_native_offset (MonoDomain *domain, MonoMethod *method, gint32 native_offset, MonoSeqPointInfo **info, SeqPoint* seq_point)
+mono_find_next_seq_point_for_native_offset (MonoDomain *domain, MonoMethod *method, gint32 native_offset, MonoSeqPointInfo **info, SeqPoint* seq_point)
 {
        MonoSeqPointInfo *seq_points;
 
-       seq_points = get_seq_points (domain, method);
+       seq_points = mono_get_seq_points (domain, method);
        if (!seq_points) {
                if (info)
                        *info = NULL;
@@ -481,20 +229,20 @@ find_next_seq_point_for_native_offset (MonoDomain *domain, MonoMethod *method, g
        if (info)
                *info = seq_points;
 
-       return seq_point_find_next_by_native_offset (seq_points, native_offset, seq_point);
+       return mono_seq_point_find_next_by_native_offset (seq_points, native_offset, seq_point);
 }
 
 /*
- * find_prev_seq_point_for_native_offset:
+ * mono_find_prev_seq_point_for_native_offset:
  *
  *   Find the first sequence point before NATIVE_OFFSET.
  */
 gboolean
-find_prev_seq_point_for_native_offset (MonoDomain *domain, MonoMethod *method, gint32 native_offset, MonoSeqPointInfo **info, SeqPoint* seq_point)
+mono_find_prev_seq_point_for_native_offset (MonoDomain *domain, MonoMethod *method, gint32 native_offset, MonoSeqPointInfo **info, SeqPoint* seq_point)
 {
        MonoSeqPointInfo *seq_points;
 
-       seq_points = get_seq_points (domain, method);
+       seq_points = mono_get_seq_points (domain, method);
        if (!seq_points) {
                if (info)
                        *info = NULL;
@@ -503,21 +251,21 @@ find_prev_seq_point_for_native_offset (MonoDomain *domain, MonoMethod *method, g
        if (info)
                *info = seq_points;
 
-       return seq_point_find_prev_by_native_offset (seq_points, native_offset, seq_point);
+       return mono_seq_point_find_prev_by_native_offset (seq_points, native_offset, seq_point);
 }
 
 /*
- * find_seq_point:
+ * mono_find_seq_point:
  *
  *   Find the sequence point corresponding to the IL offset IL_OFFSET, which
  * should be the location of a sequence point.
  */
 gboolean
-find_seq_point (MonoDomain *domain, MonoMethod *method, gint32 il_offset, MonoSeqPointInfo **info, SeqPoint *seq_point)
+mono_find_seq_point (MonoDomain *domain, MonoMethod *method, gint32 il_offset, MonoSeqPointInfo **info, SeqPoint *seq_point)
 {
        MonoSeqPointInfo *seq_points;
 
-       seq_points = get_seq_points (domain, method);
+       seq_points = mono_get_seq_points (domain, method);
        if (!seq_points) {
                if (info)
                        *info = NULL;
@@ -526,102 +274,31 @@ find_seq_point (MonoDomain *domain, MonoMethod *method, gint32 il_offset, MonoSe
        if (info)
                *info = seq_points;
 
-       return seq_point_find_by_il_offset (seq_points, il_offset, seq_point);
+       return mono_seq_point_find_by_il_offset (seq_points, il_offset, seq_point);
 }
 
 void
-seq_point_init_next (MonoSeqPointInfo* info, SeqPoint sp, SeqPoint* next)
+mono_bb_deduplicate_op_il_seq_points (MonoCompile *cfg, MonoBasicBlock *bb)
 {
-       int i;
-       guint8* ptr;
-       SeqPointIterator it;
-       GArray* seq_points = g_array_new (FALSE, TRUE, sizeof (SeqPoint));
-       SeqPointInfoInflated info_inflated = seq_point_info_inflate (info);
-
-       g_assert (info_inflated.has_debug_data);
-
-       seq_point_iterator_init (&it, info);
-       while (seq_point_iterator_next (&it))
-               g_array_append_vals (seq_points, &it.seq_point, 1);
-
-       ptr = info_inflated.data + sp.next_offset;
-       for (i = 0; i < sp.next_len; i++) {
-               int next_index;
-               next_index = decode_var_int (ptr, &ptr);
-               g_assert (next_index < seq_points->len);
-               memcpy (&next[i], seq_points->data + next_index * sizeof (SeqPoint), sizeof (SeqPoint));
-       }
+       MonoInst *ins, *n, *prev;
 
-       g_array_free (seq_points, TRUE);
-}
+       MONO_BB_FOR_EACH_INS_SAFE (bb, n, ins) {
+               if (ins->opcode != OP_IL_SEQ_POINT)
+                       continue;
 
-gboolean
-seq_point_iterator_next (SeqPointIterator* it)
-{
-       if (it->ptr >= it->end)
-               return FALSE;
+               prev = mono_inst_prev (ins, FILTER_NOP);
 
-       it->ptr += seq_point_read (&it->seq_point, it->ptr, it->begin, it->has_debug_data);
+               if (!prev || ins == prev || prev->opcode != OP_IL_SEQ_POINT)
+                       continue;
 
-       return TRUE;
+               MONO_REMOVE_INS (bb, prev);
+       };
 }
 
 void
-seq_point_iterator_init (SeqPointIterator* it, MonoSeqPointInfo* info)
-{
-       SeqPointInfoInflated info_inflated = seq_point_info_inflate (info);
-       it->ptr = info_inflated.data;
-       it->begin = info_inflated.data;
-       it->end = it->begin + info_inflated.len;
-       it->has_debug_data = info_inflated.has_debug_data;
-       memset(&it->seq_point, 0, sizeof(SeqPoint));
-}
-
-int
-seq_point_info_write (MonoSeqPointInfo* info, guint8* buffer)
-{
-       guint8* buffer0 = buffer;
-       SeqPointInfoInflated info_inflated = seq_point_info_inflate (info);
-
-       memcpy (buffer, &info_inflated.has_debug_data, 1);
-       buffer++;
-
-       //Write sequence points
-       encode_var_int (buffer, &buffer, info_inflated.len);
-       memcpy (buffer, info_inflated.data, info_inflated.len);
-       buffer += info_inflated.len;
-
-       return buffer - buffer0;
-}
-
-int
-seq_point_info_read (MonoSeqPointInfo** info, guint8* buffer, gboolean copy)
+mono_image_get_aot_seq_point_path (MonoImage *image, char **str)
 {
-       guint8* buffer0 = buffer;
-       int size;
-       gboolean has_debug_data;
-
-       memcpy (&has_debug_data, buffer, 1);
-       buffer++;
-
-       size = decode_var_int (buffer, &buffer);
-       (*info) = seq_point_info_new (size, copy, buffer, has_debug_data);
-       buffer += size;
-
-       return buffer - buffer0;
-}
-
-/*
- * Returns the maximum size of mono_seq_point_info_write.
- */
-int
-seq_point_info_get_write_size (MonoSeqPointInfo* info)
-{
-       SeqPointInfoInflated info_inflated = seq_point_info_inflate (info);
-
-       //4 is the maximum size required to store the size of the data.
-       //1 is the byte used to store has_debug_data.
-       int size = 4 + 1 + info_inflated.len;
-
-       return size;
+       int size = strlen (image->name) + strlen (SEQ_POINT_AOT_EXT) + 1;
+       *str = (char *)g_malloc (size);
+       g_sprintf (*str, "%s%s", image->name, SEQ_POINT_AOT_EXT);
 }