diff --git a/src/mono/mono/eglib/eglib-remap.h b/src/mono/mono/eglib/eglib-remap.h
index 5fc770dfa97323..3f42bd8308afca 100644
--- a/src/mono/mono/eglib/eglib-remap.h
+++ b/src/mono/mono/eglib/eglib-remap.h
@@ -98,6 +98,7 @@
 #define g_log_set_fatal_mask monoeg_g_log_set_fatal_mask
 #define g_logv monoeg_g_logv
 #define g_memdup monoeg_g_memdup
+#define g_memrchr monoeg_g_memrchr
 #define g_mem_set_vtable monoeg_g_mem_set_vtable
 #define g_mem_get_vtable monoeg_g_mem_get_vtable
 #define g_mkdtemp monoeg_g_mkdtemp
diff --git a/src/mono/mono/eglib/glib.h b/src/mono/mono/eglib/glib.h
index 7957b6949c130e..ae0dd994db2355 100644
--- a/src/mono/mono/eglib/glib.h
+++ b/src/mono/mono/eglib/glib.h
@@ -375,6 +375,7 @@ gchar       *g_strchug        (gchar *str);
 gchar       *g_strchomp       (gchar *str);
 gchar       *g_strnfill       (gsize length, gchar fill_char);
 gsize        g_strnlen        (const char*, gsize);
+const gchar *g_memrchr        (const char *s, char c, size_t n);
 
 void	     g_strdelimit     (char *string, char delimiter, char new_delimiter);
 
diff --git a/src/mono/mono/eglib/gstr.c b/src/mono/mono/eglib/gstr.c
index 6ae0eb6b668ba2..557977cab0d692 100644
--- a/src/mono/mono/eglib/gstr.c
+++ b/src/mono/mono/eglib/gstr.c
@@ -783,3 +783,12 @@ g_strnlen (const char* s, gsize n)
 	for (i = 0; i < n && s [i]; ++i) ;
 	return i;
 }
+
+const gchar *
+g_memrchr (const char *s, char c, size_t n)
+{
+	while (n--)
+		if (s[n] == c)
+			return (void *)(s + n);
+	return NULL;
+}
diff --git a/src/mono/mono/metadata/bundled-resources-internals.h b/src/mono/mono/metadata/bundled-resources-internals.h
index 1a8c03f4fb4e70..34e911ba7a1ebd 100644
--- a/src/mono/mono/metadata/bundled-resources-internals.h
+++ b/src/mono/mono/metadata/bundled-resources-internals.h
@@ -17,6 +17,7 @@ typedef enum {
 
 typedef void (*free_bundled_resource_func)(void *, void*);
 
+// WARNING: The layout of these structs cannot change because EmitBundleBase.cs depends on it!
 typedef struct _MonoBundledResource {
 	MonoBundledResourceType type;
 	const char *id;
diff --git a/src/mono/mono/metadata/bundled-resources.c b/src/mono/mono/metadata/bundled-resources.c
index 9eae4f5db8fa84..7b2f80ef3edfd7 100644
--- a/src/mono/mono/metadata/bundled-resources.c
+++ b/src/mono/mono/metadata/bundled-resources.c
@@ -8,8 +8,11 @@
 #include <mono/metadata/appdomain.h>
 #include <mono/metadata/bundled-resources-internals.h>
 #include <mono/metadata/webcil-loader.h>
+#include "../native/containers/dn-simdhash-specializations.h"
+#include "../native/containers/dn-simdhash-utils.h"
 
-static GHashTable *bundled_resources = NULL;
+static dn_simdhash_ght_t *bundled_resources = NULL;
+static dn_simdhash_ptr_ptr_t *bundled_resource_key_lookup_table = NULL;
 static bool bundled_resources_contains_assemblies = false;
 static bool bundled_resources_contains_satellite_assemblies = false;
 
@@ -31,8 +34,10 @@ mono_bundled_resources_free (void)
 {
 	g_assert (mono_runtime_is_shutting_down ());
 
-	g_hash_table_destroy (bundled_resources);
+	dn_simdhash_free (bundled_resources);
+	dn_simdhash_free (bundled_resource_key_lookup_table);
 	bundled_resources = NULL;
+	bundled_resource_key_lookup_table = NULL;
 
 	bundled_resources_contains_assemblies = false;
 	bundled_resources_contains_satellite_assemblies = false;
@@ -50,6 +55,12 @@ bundled_resources_value_destroy_func (void *resource)
 	MonoBundledResource *value = (MonoBundledResource *)resource;
 	if (value->free_func)
 		value->free_func (resource, value->free_data);
+
+	char *key;
+	if (dn_simdhash_ptr_ptr_try_get_value (bundled_resource_key_lookup_table, (void *)value->id, (void **)&key)) {
+		dn_simdhash_ptr_ptr_try_remove (bundled_resource_key_lookup_table, (void *)value->id);
+		g_free (key);
+	}
 }
 
 static bool
@@ -62,48 +73,51 @@ bundled_resources_is_known_assembly_extension (const char *ext)
 #endif
 }
 
-static gboolean
-bundled_resources_resource_id_equal (const char *id_one, const char *id_two)
+// If a bundled resource has a known assembly extension, we strip the extension from its name
+// This ensures that lookups for foo.dll will work even if the assembly is in a webcil container
+static char *
+key_from_id (const char *id, char *buffer, guint buffer_len)
 {
-	const char *extension_one = strrchr (id_one, '.');
-	const char *extension_two = strrchr (id_two, '.');
-	if (extension_one && extension_two && bundled_resources_is_known_assembly_extension (extension_one) && bundled_resources_is_known_assembly_extension (extension_two)) {
-		size_t len_one = extension_one - id_one;
-		size_t len_two = extension_two - id_two;
-		return (len_one == len_two) && !strncmp (id_one, id_two, len_one);
+	size_t id_length = strlen (id),
+		extension_offset = -1;
+	const char *extension = g_memrchr (id, '.', id_length);
+	if (extension)
+		extension_offset = extension - id;
+	if (!buffer) {
+		// Add space for .dll and null terminator
+		buffer_len = (guint)(id_length + 6);
+		buffer = g_malloc (buffer_len);
 	}
+	buffer[0] = 0;
 
-	return !strcmp (id_one, id_two);
+	if (extension_offset && bundled_resources_is_known_assembly_extension (extension)) {
+		// Subtract from buffer_len to make sure we have space for .dll
+		g_strlcpy (buffer, id, MIN(buffer_len - 4, extension_offset + 2));
+		strcat (buffer, "dll");
+	} else {
+		g_strlcpy (buffer, id, MIN(buffer_len, id_length + 1));
+	}
+
+	return buffer;
 }
 
-static guint
-bundled_resources_resource_id_hash (const char *id)
+static gboolean
+bundled_resources_resource_id_equal (const char *key_one, const char *key_two)
 {
-	const char *current = id;
-	const char *extension = NULL;
-	guint previous_hash = 0;
-	guint hash = 0;
-
-	while (*current) {
-		hash = (hash << 5) - (hash + *current);
-		if (*current == '.') {
-			extension = current;
-			previous_hash = hash;
-		}
-		current++;
-	}
-
-	// alias all extensions to .dll
-	if (extension && bundled_resources_is_known_assembly_extension (extension)) {
-		hash = previous_hash;
-		hash = (hash << 5) - (hash + 'd');
-		hash = (hash << 5) - (hash + 'l');
-		hash = (hash << 5) - (hash + 'l');
-	}
+	return strcmp (key_one, key_two) == 0;
+}
 
-	return hash;
+static guint32
+bundled_resources_resource_id_hash (const char *key)
+{
+	// FIXME: Seed
+	// FIXME: We should cache the hash code so rehashes are cheaper
+	return MurmurHash3_32_streaming ((const uint8_t *)key, 0);
 }
 
+static MonoBundledResource *
+bundled_resources_get (const char *id);
+
 //---------------------------------------------------------------------------------------
 //
 // mono_bundled_resources_add handles bundling of many types of resources to circumvent
@@ -130,7 +144,11 @@ mono_bundled_resources_add (MonoBundledResource **resources_to_bundle, uint32_t
 	g_assert (!domain);
 
 	if (!bundled_resources)
-		bundled_resources = g_hash_table_new_full ((GHashFunc)bundled_resources_resource_id_hash, (GEqualFunc)bundled_resources_resource_id_equal, NULL, bundled_resources_value_destroy_func);
+		// FIXME: Choose a good initial capacity to avoid rehashes during startup. I picked one at random
+		bundled_resources = dn_simdhash_ght_new_full ((GHashFunc)bundled_resources_resource_id_hash, (GEqualFunc)bundled_resources_resource_id_equal, NULL, bundled_resources_value_destroy_func, 2048, NULL);
+
+	if (!bundled_resource_key_lookup_table)
+		bundled_resource_key_lookup_table = dn_simdhash_ptr_ptr_new (2048, NULL);
 
 	bool assemblyAdded = false;
 	bool satelliteAssemblyAdded = false;
@@ -143,7 +161,13 @@ mono_bundled_resources_add (MonoBundledResource **resources_to_bundle, uint32_t
 		if (resource_to_bundle->type == MONO_BUNDLED_SATELLITE_ASSEMBLY)
 			satelliteAssemblyAdded = true;
 
-		g_hash_table_insert (bundled_resources, (gpointer) resource_to_bundle->id, resource_to_bundle);
+		// Generate the hash key for the id (strip certain extensions) and store it
+		//  so that we can free it later when freeing the bundled data
+		char *key = key_from_id (resource_to_bundle->id, NULL, 0);
+		dn_simdhash_ptr_ptr_try_add (bundled_resource_key_lookup_table, (void *)resource_to_bundle->id, key);
+
+		g_assert (dn_simdhash_ght_try_add (bundled_resources, (gpointer) key, resource_to_bundle));
+		// g_assert (bundled_resources_get (resource_to_bundle->id) == resource_to_bundle);
 	}
 
 	if (assemblyAdded)
@@ -172,7 +196,12 @@ bundled_resources_get (const char *id)
 	if (!bundled_resources)
 		return NULL;
 
-	return g_hash_table_lookup (bundled_resources, id);
+	char key_buffer[1024];
+	key_from_id(id, key_buffer, sizeof(key_buffer));
+
+	MonoBundledResource *result = NULL;
+	dn_simdhash_ght_try_get_value (bundled_resources, key_buffer, (void **)&result);
+	return result;
 }
 
 //---------------------------------------------------------------------------------------
@@ -364,9 +393,7 @@ bool
 mono_bundled_resources_get_data_resource_values (const char *id, const uint8_t **data_out, uint32_t *size_out)
 {
 	MonoBundledDataResource *bundled_data_resource = bundled_resources_get_data_resource (id);
-	if (!bundled_data_resource ||
-		!bundled_data_resource->data.data ||
-		bundled_data_resource->data.size == 0)
+	if (!bundled_data_resource || !bundled_data_resource->data.data)
 		return false;
 
 	if (data_out)