Completely replace mono_error_ok with is_ok and make first external_only. (#16217)
[mono-project.git] / mono / metadata / seq-points-data.c
blobd911258e75a894f400248c7ac0920e4cc465950e
1 /**
2 * \file
3 * Sequence Points functions
5 * Authors:
6 * Marcos Henrich (marcos.henrich@xamarin.com)
8 * Copyright 2015 Xamarin, Inc (http://www.xamarin.com)
9 */
11 #include "seq-points-data.h"
13 typedef struct {
14 guint8 *data;
15 int len;
16 /* When has_debug_data is set to false only il and native deltas are saved */
17 gboolean has_debug_data;
18 /* When alloc_data is set to true data allocation/deallocation is managed by this structure */
19 gboolean alloc_data;
20 } SeqPointInfoInflated;
22 static int
23 encode_var_int (guint8 *buf, guint8 **out_buf, int val)
25 guint8 size = 0;
27 do {
28 guint8 byte = val & 0x7f;
29 g_assert (size < 4 && "value has more than 28 bits");
30 val >>= 7;
31 if(val) byte |= 0x80;
32 *(buf++) = byte;
33 size++;
34 } while (val);
36 if (out_buf)
37 *out_buf = buf;
39 return size;
42 static int
43 decode_var_int (guint8* buf, guint8 **out_buf)
45 guint8* p = buf;
47 int low;
48 int b;
49 b = *(p++); low = (b & 0x7f) ; if(!(b & 0x80)) goto done;
50 b = *(p++); low |= (b & 0x7f) << 7; if(!(b & 0x80)) goto done;
51 b = *(p++); low |= (b & 0x7f) << 14; if(!(b & 0x80)) goto done;
52 b = *(p++); low |= (b & 0x7f) << 21; if(!(b & 0x80)) goto done;
54 g_assert (FALSE && "value has more than 28 bits");
56 done:
58 if (out_buf)
59 *out_buf = p;
61 return low;
64 static guint32
65 encode_zig_zag (int val)
67 return (val << 1) ^ (val >> 31);
70 static int
71 decode_zig_zag (guint32 val)
73 int n = val;
74 return (n >> 1) ^ (-(n & 1));
77 static SeqPointInfoInflated
78 seq_point_info_inflate (MonoSeqPointInfo *info)
80 SeqPointInfoInflated info_inflated;
81 guint8 *ptr = (guint8*) info;
82 int value;
84 value = decode_var_int (ptr, &ptr);
86 info_inflated.len = value >> 2;
87 info_inflated.has_debug_data = (value & 1) != 0;
88 info_inflated.alloc_data = (value & 2) != 0;
90 if (info_inflated.alloc_data)
91 info_inflated.data = ptr;
92 else
93 memcpy (&info_inflated.data, ptr, sizeof (guint8*));
95 return info_inflated;
98 MonoSeqPointInfo*
99 mono_seq_point_info_new (int len, gboolean alloc_data, guint8 *data, gboolean has_debug_data, int *out_size)
101 MonoSeqPointInfo *info;
102 guint8 *info_ptr;
103 guint8 buffer[4];
104 int buffer_len;
105 int value;
106 int data_size;
108 value = len << 2;
109 if (has_debug_data)
110 value |= 1;
111 if (alloc_data)
112 value |= 2;
114 buffer_len = encode_var_int (buffer, NULL, value);
116 *out_size = data_size = buffer_len + (alloc_data? len : sizeof (guint8*));
117 info_ptr = g_new0 (guint8, data_size);
118 info = (MonoSeqPointInfo*) info_ptr;
120 memcpy (info_ptr, buffer, buffer_len);
121 info_ptr += buffer_len;
123 if (alloc_data)
124 memcpy (info_ptr, data, len);
125 else
126 memcpy (info_ptr, &data, sizeof (guint8*));
128 return info;
131 void
132 mono_seq_point_info_free (gpointer ptr)
134 MonoSeqPointInfo* info = (MonoSeqPointInfo*) ptr;
135 g_free (info);
138 static int
139 seq_point_read (SeqPoint* seq_point, guint8* ptr, guint8* buffer_ptr, gboolean has_debug_data)
141 int value, i;
142 guint8* ptr0 = ptr;
144 value = decode_var_int (ptr, &ptr);
145 seq_point->il_offset += decode_zig_zag (value);
147 value = decode_var_int (ptr, &ptr);
148 seq_point->native_offset += decode_zig_zag (value);
150 if (has_debug_data) {
151 value = decode_var_int (ptr, &ptr);
152 seq_point->flags = value;
154 if (seq_point->flags & MONO_SEQ_POINT_FLAG_EXIT_IL)
155 seq_point->il_offset = METHOD_EXIT_IL_OFFSET;
157 value = decode_var_int (ptr, &ptr);
158 seq_point->next_len = value;
160 if (seq_point->next_len) {
161 // store next offset and skip it
162 seq_point->next_offset = ptr - buffer_ptr;
163 for (i = 0; i < seq_point->next_len; ++i)
164 decode_var_int (ptr, &ptr);
168 return ptr - ptr0;
171 gboolean
172 mono_seq_point_info_add_seq_point (GByteArray* array, SeqPoint *sp, SeqPoint *last_seq_point, GSList *next, gboolean has_debug_data)
174 int il_delta, native_delta;
175 GSList *l;
176 guint8 buffer[4];
177 guint8 len;
178 int flags;
180 if (!has_debug_data &&
181 (sp->il_offset == METHOD_ENTRY_IL_OFFSET || sp->il_offset == METHOD_EXIT_IL_OFFSET))
182 return FALSE;
184 il_delta = sp->il_offset - last_seq_point->il_offset;
185 native_delta = sp->native_offset - last_seq_point->native_offset;
187 flags = sp->flags;
189 if (has_debug_data && sp->il_offset == METHOD_EXIT_IL_OFFSET) {
190 il_delta = 0;
191 flags |= MONO_SEQ_POINT_FLAG_EXIT_IL;
194 len = encode_var_int (buffer, NULL, encode_zig_zag (il_delta));
195 g_byte_array_append (array, buffer, len);
197 len = encode_var_int (buffer, NULL, encode_zig_zag (native_delta));
198 g_byte_array_append (array, buffer, len);
200 if (has_debug_data) {
201 sp->next_offset = array->len;
202 sp->next_len = g_slist_length (next);
204 len = encode_var_int (buffer, NULL, flags);
205 g_byte_array_append (array, buffer, len);
207 len = encode_var_int (buffer, NULL, sp->next_len);
208 g_byte_array_append (array, buffer, len);
210 for (l = next; l; l = l->next) {
211 int next_index = GPOINTER_TO_UINT (l->data);
212 guint8 buffer[4];
213 int len = encode_var_int (buffer, NULL, next_index);
214 g_byte_array_append (array, buffer, len);
218 return TRUE;
221 gboolean
222 mono_seq_point_find_next_by_native_offset (MonoSeqPointInfo* info, int native_offset, SeqPoint* seq_point)
224 SeqPointIterator it;
225 mono_seq_point_iterator_init (&it, info);
226 while (mono_seq_point_iterator_next (&it)) {
227 if (it.seq_point.native_offset >= native_offset) {
228 memcpy (seq_point, &it.seq_point, sizeof (SeqPoint));
229 return TRUE;
233 return FALSE;
236 gboolean
237 mono_seq_point_find_prev_by_native_offset (MonoSeqPointInfo* info, int native_offset, SeqPoint* seq_point)
239 SeqPoint prev_seq_point;
240 gboolean is_first = TRUE;
241 SeqPointIterator it;
242 mono_seq_point_iterator_init (&it, info);
243 while (mono_seq_point_iterator_next (&it) && it.seq_point.native_offset <= native_offset) {
244 memcpy (&prev_seq_point, &it.seq_point, sizeof (SeqPoint));
245 is_first = FALSE;
248 if (!is_first && prev_seq_point.native_offset <= native_offset) {
249 memcpy (seq_point, &prev_seq_point, sizeof (SeqPoint));
250 return TRUE;
253 return FALSE;
256 gboolean
257 mono_seq_point_find_by_il_offset (MonoSeqPointInfo* info, int il_offset, SeqPoint* seq_point)
259 SeqPointIterator it;
260 mono_seq_point_iterator_init (&it, info);
261 while (mono_seq_point_iterator_next (&it)) {
262 if (it.seq_point.il_offset == il_offset) {
263 memcpy (seq_point, &it.seq_point, sizeof (SeqPoint));
264 return TRUE;
268 return FALSE;
271 void
272 mono_seq_point_init_next (MonoSeqPointInfo* info, SeqPoint sp, SeqPoint* next)
274 int i;
275 guint8* ptr;
276 SeqPointIterator it;
277 GArray* seq_points = g_array_new (FALSE, TRUE, sizeof (SeqPoint));
278 SeqPointInfoInflated info_inflated = seq_point_info_inflate (info);
280 g_assert (info_inflated.has_debug_data);
282 mono_seq_point_iterator_init (&it, info);
283 while (mono_seq_point_iterator_next (&it))
284 g_array_append_vals (seq_points, &it.seq_point, 1);
286 ptr = info_inflated.data + sp.next_offset;
287 for (i = 0; i < sp.next_len; i++) {
288 int next_index;
289 next_index = decode_var_int (ptr, &ptr);
290 g_assert (next_index < seq_points->len);
291 memcpy (&next[i], seq_points->data + next_index * sizeof (SeqPoint), sizeof (SeqPoint));
294 g_array_free (seq_points, TRUE);
297 gboolean
298 mono_seq_point_iterator_next (SeqPointIterator* it)
300 if (it->ptr >= it->end)
301 return FALSE;
303 it->ptr += seq_point_read (&it->seq_point, it->ptr, it->begin, it->has_debug_data);
305 return TRUE;
308 void
309 mono_seq_point_iterator_init (SeqPointIterator* it, MonoSeqPointInfo* info)
311 SeqPointInfoInflated info_inflated = seq_point_info_inflate (info);
312 it->ptr = info_inflated.data;
313 it->begin = info_inflated.data;
314 it->end = it->begin + info_inflated.len;
315 it->has_debug_data = info_inflated.has_debug_data;
316 memset(&it->seq_point, 0, sizeof(SeqPoint));
320 mono_seq_point_info_write (MonoSeqPointInfo* info, guint8* buffer)
322 guint8* buffer0 = buffer;
323 SeqPointInfoInflated info_inflated = seq_point_info_inflate (info);
325 encode_var_int (buffer, &buffer, info_inflated.has_debug_data);
327 //Write sequence points
328 encode_var_int (buffer, &buffer, info_inflated.len);
329 memcpy (buffer, info_inflated.data, info_inflated.len);
330 buffer += info_inflated.len;
332 return buffer - buffer0;
336 mono_seq_point_info_read (MonoSeqPointInfo** info, guint8* buffer, gboolean copy)
338 guint8* buffer0 = buffer;
339 int size, info_size;
340 gboolean has_debug_data;
342 has_debug_data = decode_var_int (buffer, &buffer);
344 size = decode_var_int (buffer, &buffer);
345 (*info) = mono_seq_point_info_new (size, copy, buffer, has_debug_data, &info_size);
346 buffer += size;
348 return buffer - buffer0;
352 * Returns the maximum size of mono_seq_point_info_write.
355 mono_seq_point_info_get_write_size (MonoSeqPointInfo* info)
357 SeqPointInfoInflated info_inflated = seq_point_info_inflate (info);
359 //4 is the maximum size required to store the size of the data.
360 //1 is the byte used to store has_debug_data.
361 int size = 4 + 1 + info_inflated.len;
363 return size;
367 * SeqPointData struct and functions
368 * This is used to store/load/use sequence point from a file
371 void
372 mono_seq_point_data_init (SeqPointData *data, int entry_capacity)
374 data->entry_count = 0;
375 data->entry_capacity = entry_capacity;
376 data->entries = (SeqPointDataEntry *)g_malloc (sizeof (SeqPointDataEntry) * entry_capacity);
379 void
380 mono_seq_point_data_free (SeqPointData *data)
382 int i;
383 for (i=0; i<data->entry_count; i++) {
384 if (data->entries [i].free_seq_points)
385 g_free (data->entries [i].seq_points);
387 g_free (data->entries);
390 gboolean
391 mono_seq_point_data_read (SeqPointData *data, char *path)
393 guint8 *buffer, *buffer_orig;
394 int entry_count, i;
395 long fsize;
396 FILE *f;
398 f = fopen (path, "r");
399 if (!f)
400 return FALSE;
402 fseek(f, 0, SEEK_END);
403 fsize = ftell(f);
404 if (fsize == -1){
405 fclose (f);
406 return FALSE;
409 fseek(f, 0, SEEK_SET);
411 buffer_orig = buffer = (guint8 *)g_malloc (fsize + 1);
412 fread(buffer_orig, fsize, 1, f);
413 fclose(f);
415 entry_count = decode_var_int (buffer, &buffer);
416 mono_seq_point_data_init (data, entry_count);
417 data->entry_count = entry_count;
419 for (i=0; i<entry_count; i++) {
420 data->entries [i].method_token = decode_var_int (buffer, &buffer);
421 data->entries [i].method_index = decode_var_int (buffer, &buffer);
422 buffer += mono_seq_point_info_read (&data->entries [i].seq_points, buffer, TRUE);
423 data->entries [i].free_seq_points = TRUE;
426 g_free (buffer_orig);
427 return TRUE;
430 gboolean
431 mono_seq_point_data_write (SeqPointData *data, char *path)
433 guint8 *buffer, *buffer_orig;
434 FILE *f;
435 int i, size = 0;
437 f = fopen (path, "w+");
438 if (!f)
439 return FALSE;
441 for (i=0; i<data->entry_count; i++) {
442 size += mono_seq_point_info_get_write_size (data->entries [i].seq_points);
444 // Add size of entry_count and native_base_offsets
445 size += 4 + data->entry_count * 4;
447 buffer_orig = buffer = (guint8 *)g_malloc (size);
449 encode_var_int (buffer, &buffer, data->entry_count);
451 for (i=0; i<data->entry_count; i++) {
452 encode_var_int (buffer, &buffer, data->entries [i].method_token);
453 encode_var_int (buffer, &buffer, data->entries [i].method_index);
454 buffer += mono_seq_point_info_write (data->entries [i].seq_points, buffer);
457 fwrite (buffer_orig, 1, buffer - buffer_orig, f);
458 g_free (buffer_orig);
459 fclose (f);
461 return TRUE;
464 void
465 mono_seq_point_data_add (SeqPointData *data, guint32 method_token, guint32 method_index, MonoSeqPointInfo* info)
467 int i;
469 g_assert (data->entry_count < data->entry_capacity);
470 i = data->entry_count++;
471 data->entries [i].seq_points = info;
472 data->entries [i].method_token = method_token;
473 data->entries [i].method_index = method_index;
474 data->entries [i].free_seq_points = FALSE;
477 gboolean
478 mono_seq_point_data_get (SeqPointData *data, guint32 method_token, guint32 method_index, MonoSeqPointInfo** info)
480 int i;
482 for (i=0; i<data->entry_count; i++) {
483 if (data->entries [i].method_token == method_token && (method_index == 0xffffff || data->entries [i].method_index == method_index)) {
484 (*info) = data->entries [i].seq_points;
485 return TRUE;
488 return FALSE;
491 gboolean
492 mono_seq_point_data_get_il_offset (char *path, guint32 method_token, guint32 method_index, guint32 native_offset, guint32 *il_offset)
494 SeqPointData sp_data;
495 MonoSeqPointInfo *seq_points;
496 SeqPoint sp;
498 if (!mono_seq_point_data_read (&sp_data, path))
499 return FALSE;
501 if (!mono_seq_point_data_get (&sp_data, method_token, method_index, &seq_points))
502 return FALSE;
504 if (!mono_seq_point_find_prev_by_native_offset (seq_points, native_offset, &sp))
505 return FALSE;
507 *il_offset = sp.il_offset;
509 return TRUE;