Skip to content

Commit

Permalink
optimize adding unwind info entries by hashtable (#55398)
Browse files Browse the repository at this point in the history
  • Loading branch information
DzmitryKN committed Jul 13, 2021
1 parent dfd618d commit c6acf8d
Showing 1 changed file with 67 additions and 34 deletions.
101 changes: 67 additions & 34 deletions src/mono/mono/mini/unwind.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,15 @@ typedef struct {

typedef struct {
guint32 len;
guint8 info [MONO_ZERO_LEN_ARRAY];
guint8 *info;
} MonoUnwindInfo;

static mono_mutex_t unwind_mutex;

static MonoUnwindInfo **cached_info;
static MonoUnwindInfo *cached_info;
static int cached_info_next, cached_info_size;
static GSList *cached_info_list;
static GHashTable *cached_info_ht;
/* Statistics */
static int unwind_info_size;

Expand Down Expand Up @@ -729,6 +730,34 @@ mono_unwind_init (void)
mono_counters_register ("Unwind info size", MONO_COUNTER_JIT | MONO_COUNTER_INT, &unwind_info_size);
}

static guint
cached_info_hash(gconstpointer key)
{
guint i, a;
const guint8 *info = cached_info [GPOINTER_TO_UINT (key)].info;
const guint len = cached_info [GPOINTER_TO_UINT (key)].len;

for (i = a = 0; i != len; ++i)
a ^= (((guint)info [i]) << (i & 0xf));

return a;
}

static gboolean
cached_info_eq(gconstpointer a, gconstpointer b)
{
const guint32 lena = cached_info [GPOINTER_TO_UINT (a)].len;
const guint32 lenb = cached_info [GPOINTER_TO_UINT (b)].len;
if (lena == lenb) {
const guint8 *infoa = cached_info [GPOINTER_TO_UINT (a)].info;
const guint8 *infob = cached_info [GPOINTER_TO_UINT (b)].info;
if (memcmp (infoa, infob, lena) == 0)
return TRUE;
}

return FALSE;
}

/*
* mono_cache_unwind_info
*
Expand All @@ -742,57 +771,64 @@ mono_unwind_init (void)
guint32
mono_cache_unwind_info (guint8 *unwind_info, guint32 unwind_info_len)
{
int i;
MonoUnwindInfo *info;

gpointer orig_key;
guint32 i;
unwind_lock ();

if (cached_info == NULL) {
cached_info_size = 16;
cached_info = g_new0 (MonoUnwindInfo*, cached_info_size);
}

for (i = 0; i < cached_info_next; ++i) {
MonoUnwindInfo *cached = cached_info [i];

if (cached->len == unwind_info_len && memcmp (cached->info, unwind_info, unwind_info_len) == 0) {
unwind_unlock ();
return i;
}
}
if (!cached_info_ht)
cached_info_ht = g_hash_table_new (cached_info_hash, cached_info_eq);

info = (MonoUnwindInfo *)g_malloc (sizeof (MonoUnwindInfo) + unwind_info_len);
info->len = unwind_info_len;
memcpy (&info->info, unwind_info, unwind_info_len);

i = cached_info_next;

if (cached_info_next >= cached_info_size) {
MonoUnwindInfo **new_table;
MonoUnwindInfo *new_table;
int new_cached_info_size = cached_info_size ? cached_info_size * 2 : 16;

/* ensure no integer overflow */
g_assert (new_cached_info_size > cached_info_size);

/*
* Avoid freeing the old table so mono_get_cached_unwind_info ()
* doesn't need locks/hazard pointers.
*/
new_table = g_new0 (MonoUnwindInfo, new_cached_info_size );

new_table = g_new0 (MonoUnwindInfo*, cached_info_size * 2);
/* include array allocations into statistics of memory totally consumed by unwind info */
unwind_info_size += sizeof (MonoUnwindInfo) * new_cached_info_size ;

memcpy (new_table, cached_info, cached_info_size * sizeof (MonoUnwindInfo*));
if (cached_info_size)
memcpy (new_table, cached_info, sizeof (MonoUnwindInfo) * cached_info_size);

mono_memory_barrier ();

cached_info_list = g_slist_prepend (cached_info_list, cached_info);

cached_info = new_table;

cached_info_size *= 2;
cached_info_size = new_cached_info_size;
}

cached_info [cached_info_next ++] = info;
i = cached_info_next;

/* construct temporary element at array's edge without allocated info copy - it will be used for hashtable lookup */
cached_info [i].len = unwind_info_len;
cached_info [i].info = unwind_info;

unwind_info_size += sizeof (MonoUnwindInfo) + unwind_info_len;
if (!g_hash_table_lookup_extended (cached_info_ht, GUINT_TO_POINTER (i), &orig_key, NULL) ) {
/* hashtable lookup didnt find match - now need to really add new element with allocated copy of unwind info */
cached_info [i].info = g_new (guint8, unwind_info_len);
memcpy (cached_info [i].info, unwind_info, unwind_info_len);

/* include allocated memory in stats, note that hashtable allocates struct of 3 pointers per each entry */
unwind_info_size += sizeof (void *) * 3 + unwind_info_len;
g_hash_table_insert_replace (cached_info_ht, GUINT_TO_POINTER (i), NULL, TRUE);

cached_info_next = i + 1;

} else {
i = GPOINTER_TO_UINT (orig_key);
}

unwind_unlock ();

return i;
}

Expand All @@ -802,17 +838,14 @@ mono_cache_unwind_info (guint8 *unwind_info, guint32 unwind_info_len)
guint8*
mono_get_cached_unwind_info (guint32 index, guint32 *unwind_info_len)
{
MonoUnwindInfo **table;
MonoUnwindInfo *info;
guint8 *data;

/*
* This doesn't need any locks/hazard pointers,
* since new tables are copies of the old ones.
*/
table = cached_info;

info = table [index];
info = &cached_info [index];

*unwind_info_len = info->len;
data = info->info;
Expand Down

0 comments on commit c6acf8d

Please sign in to comment.