Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/dotnet/runtime.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDzmitry Konanka <85848222+DzmitryKN@users.noreply.github.com>2021-07-13 18:02:43 +0300
committerGitHub <noreply@github.com>2021-07-13 18:02:43 +0300
commitc6acf8dbeff5e2c54b055f496cb8dafc5d0b3e20 (patch)
treee0420afb4f59d6a9cbbf3d68246dcdac9bbc80b8 /src
parentdfd618dc648ba9b11dd0f8034f78113d69f223cd (diff)
optimize adding unwind info entries by hashtable (#55398)
Diffstat (limited to 'src')
-rw-r--r--src/mono/mono/mini/unwind.c101
1 files changed, 67 insertions, 34 deletions
diff --git a/src/mono/mono/mini/unwind.c b/src/mono/mono/mini/unwind.c
index bcf9bd4682e..bdcfe78604b 100644
--- a/src/mono/mono/mini/unwind.c
+++ b/src/mono/mono/mini/unwind.c
@@ -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;
@@ -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
*
@@ -742,42 +771,31 @@ 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 ();
@@ -785,14 +803,32 @@ mono_cache_unwind_info (guint8 *unwind_info, guint32 unwind_info_len)
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;
}
@@ -802,7 +838,6 @@ 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;
@@ -810,9 +845,7 @@ mono_get_cached_unwind_info (guint32 index, guint32 *unwind_info_len)
* 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;