Created
April 7, 2021 18:53
-
-
Save MasterDuke17/f5f5e45e3199c1f714628a39dbfd38ff to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git src/core/dll.c src/core/dll.c | |
index 6817b410f..3b1ea0269 100644 | |
--- src/core/dll.c | |
+++ src/core/dll.c | |
@@ -23,6 +23,7 @@ int MVM_dll_load(MVMThreadContext *tc, MVMString *name, MVMString *path) { | |
}); | |
cpath = MVM_string_utf8_c8_encode_C_string(tc, path); | |
+ fprintf(stderr, "loading '%s'\n", cpath); | |
lib = MVM_nativecall_load_lib(cpath); | |
if (!lib) { | |
@@ -44,10 +45,24 @@ int MVM_dll_load(MVMThreadContext *tc, MVMString *name, MVMString *path) { | |
uv_mutex_unlock(&tc->instance->mutex_dll_registry); | |
+ MVMFixKeyHashTable *const dll_registry = &tc->instance->dll_registry; | |
+ MVMFixKeyHashIterator iterator = MVM_fixkey_hash_first(tc, dll_registry); | |
+ while (!MVM_fixkey_hash_at_end(tc, dll_registry, iterator)) { | |
+ fprintf(stderr, "freeing a dll\n"); | |
+ MVMDLLRegistry *entry = MVM_fixkey_hash_current_nocheck(tc, dll_registry, iterator); | |
+ //MVMDLLRegistry *entry = MVM_fixkey_hash_fetch_nocheck(instance->main_thread, dll_registry, name); | |
+ if (entry && entry->lib) { | |
+ fprintf(stderr, "for realz\n"); | |
+ //MVM_nativecall_free_lib(entry->lib); | |
+ } | |
+ iterator = MVM_fixkey_hash_next_nocheck(tc, dll_registry, iterator); | |
+ } | |
+ uv_mutex_unlock(&tc->instance->mutex_dll_registry); | |
return 1; | |
} | |
int MVM_dll_free(MVMThreadContext *tc, MVMString *name) { | |
+ fprintf(stderr, "freeing lib'\n"); | |
if (!MVM_str_hash_key_is_valid(tc, name)) { | |
MVM_str_hash_key_throw_invalid(tc, name); | |
} | |
diff --git src/core/fixkey_hash_table.h src/core/fixkey_hash_table.h | |
index 2e24be325..2290d2a4e 100644 | |
--- src/core/fixkey_hash_table.h | |
+++ src/core/fixkey_hash_table.h | |
@@ -44,6 +44,11 @@ Not all the optimisations described above are in place yet. Starting with | |
*/ | |
struct MVMFixKeyHashTableControl { | |
+#if HASH_DEBUG_ITER | |
+ MVMuint64 ht_id; | |
+ MVMuint32 serial; | |
+ MVMuint32 last_delete_at; | |
+#endif | |
MVMHashNumItems cur_items; | |
MVMHashNumItems max_items; /* hit this and we grow */ | |
MVMuint16 entry_size; | |
@@ -63,3 +68,52 @@ struct MVMFixKeyHashTableControl { | |
struct MVMFixKeyHashTable { | |
struct MVMFixKeyHashTableControl *table; | |
}; | |
+ | |
+typedef struct { | |
+ MVMuint32 pos; | |
+#if HASH_DEBUG_ITER | |
+ MVMuint32 serial; | |
+ MVMuint64 owner; | |
+#endif | |
+} MVMFixKeyHashIterator; | |
+ | |
+#if HASH_DEBUG_ITER | |
+MVM_STATIC_INLINE int MVM_fixkey_hash_iterator_target_deleted(MVMThreadContext *tc, | |
+ MVMFixKeyHashTable *hashtable, | |
+ MVMFixKeyHashIterator iterator) { | |
+ /* Returns true if the hash entry that the iterator points to has been | |
+ * deleted (and this is the only action on the hash since the iterator was | |
+ * created) */ | |
+ struct MVMFixKeyHashTableControl *control = hashtable->table; | |
+ return control && iterator.serial == control->serial - 1 && | |
+ iterator.pos == control->last_delete_at; | |
+} | |
+#endif | |
+ | |
+/* So why is this here, instead of _funcs? | |
+ * Because it is needed in MVM_iter_istrue_hash, which is inline in MVMIter.h | |
+ * So this definition has to be before that definition. | |
+ * In turn, various other inline functions in the reprs are used in | |
+ * fixkey_hash_table_funcs.h, so those declarations have to be seen already, and | |
+ * as the reprs headers are included as one block, *most* of the MVMFixKeyHashTable | |
+ * functions need to be later. */ | |
+ | |
+MVM_STATIC_INLINE int MVM_fixkey_hash_at_end(MVMThreadContext *tc, | |
+ MVMFixKeyHashTable *hashtable, | |
+ MVMFixKeyHashIterator iterator) { | |
+#if HASH_DEBUG_ITER | |
+ struct MVMFixKeyHashTableControl *control = hashtable->table; | |
+ MVMuint64 ht_id = control ? control->ht_id : 0; | |
+ if (iterator.owner != ht_id) { | |
+ MVM_oops(tc, "MVM_fixkey_hash_at_end called with an iterator from a different hash table: %016" PRIx64 " != %016" PRIx64, | |
+ iterator.owner, ht_id); | |
+ } | |
+ MVMuint32 serial = control ? control->serial : 0; | |
+ if (iterator.serial != serial | |
+ || MVM_fixkey_hash_iterator_target_deleted(tc, hashtable, iterator)) { | |
+ MVM_oops(tc, "MVM_fixkey_hash_at_end called with an iterator with the wrong serial number: %u != %u", | |
+ iterator.serial, serial); | |
+ } | |
+#endif | |
+ return iterator.pos == 0; | |
+} | |
diff --git src/core/fixkey_hash_table_funcs.h src/core/fixkey_hash_table_funcs.h | |
index d1753f995..27efeaad9 100644 | |
--- src/core/fixkey_hash_table_funcs.h | |
+++ src/core/fixkey_hash_table_funcs.h | |
@@ -18,6 +18,10 @@ MVM_STATIC_INLINE MVMuint32 MVM_fixkey_hash_official_size(const struct MVMFixKey | |
MVM_STATIC_INLINE MVMuint32 MVM_fixkey_hash_allocated_items(const struct MVMFixKeyHashTableControl *control) { | |
return MVM_fixkey_hash_official_size(control) + control->max_probe_distance_limit - 1; | |
} | |
+MVM_STATIC_INLINE MVMuint32 MVM_fixkey_hash_kompromat(const struct MVMFixKeyHashTableControl *control) { | |
+ assert(!(control->cur_items == 0 && control->max_items == 0)); | |
+ return MVM_fixkey_hash_official_size(control) + control->max_probe_distance - 1; | |
+} | |
MVM_STATIC_INLINE MVMuint32 MVM_fixkey_hash_max_items(const struct MVMFixKeyHashTableControl *control) { | |
return MVM_fixkey_hash_official_size(control) * MVM_FIXKEY_HASH_LOAD_FACTOR; | |
} | |
@@ -131,3 +135,161 @@ MVM_STATIC_INLINE void *MVM_fixkey_hash_fetch_nocheck(MVMThreadContext *tc, | |
void *MVM_fixkey_hash_lvalue_fetch_nocheck(MVMThreadContext *tc, | |
MVMFixKeyHashTable *hashtable, | |
MVMString *key); | |
+/* iterators are stored as unsigned values, metadata index plus one. | |
+ * This is clearly an internal implementation detail. Don't cheat. | |
+ */ | |
+ | |
+/* Only call this if MVM_fixkey_hash_at_end returns false. */ | |
+MVM_STATIC_INLINE MVMFixKeyHashIterator MVM_fixkey_hash_next_nocheck(MVMThreadContext *tc, | |
+ MVMFixKeyHashTable *hashtable, | |
+ MVMFixKeyHashIterator iterator) { | |
+ struct MVMFixKeyHashTableControl *control = hashtable->table; | |
+ /* Whilst this looks like it can be optimised to word at a time skip ahead. | |
+ * (Beware of endianness) it isn't easy *yet*, because one can overrun the | |
+ * allocated buffer, and that makes ASAN very excited. */ | |
+ while (--iterator.pos > 0) { | |
+ if (MVM_fixkey_hash_metadata(control)[iterator.pos - 1]) { | |
+ return iterator; | |
+ } | |
+ } | |
+ return iterator; | |
+} | |
+ | |
+MVM_STATIC_INLINE MVMFixKeyHashIterator MVM_fixkey_hash_next(MVMThreadContext *tc, | |
+ MVMFixKeyHashTable *hashtable, | |
+ MVMFixKeyHashIterator iterator) { | |
+#if HASH_DEBUG_ITER | |
+ struct MVMFixKeyHashTableControl *control = hashtable->table; | |
+ if (iterator.owner != control->ht_id) { | |
+ MVM_oops(tc, "MVM_fixkey_hash_next called with an iterator from a different hash table: %016" PRIx64 " != %016" PRIx64, | |
+ iterator.owner, control->ht_id); | |
+ } | |
+ /* "the usual case" is that the iterator serial number matches the hash | |
+ * serial number. | |
+ * As we permit deletes at the current iterator, we also track whether the | |
+ * last mutation on the hash was a delete, and if so record where. Hence, | |
+ * if the hash serial has advanced by one, and the last delete was at this | |
+ * iterator's current bucket position, that's OK too. */ | |
+ if (!(iterator.serial == control->serial | |
+ || (iterator.serial == control->serial - 1 && | |
+ iterator.pos == control->last_delete_at))) { | |
+ MVM_oops(tc, "MVM_fixkey_hash_next called with an iterator with the wrong serial number: %u != %u", | |
+ iterator.serial, control->serial); | |
+ } | |
+#endif | |
+ | |
+ if (iterator.pos == 0) { | |
+ MVM_oops(tc, "Calling fixkey_hash_next when iterator is already at the end"); | |
+ } | |
+ | |
+ return MVM_fixkey_hash_next_nocheck(tc, hashtable, iterator); | |
+} | |
+ | |
+MVM_STATIC_INLINE MVMFixKeyHashIterator MVM_fixkey_hash_first(MVMThreadContext *tc, | |
+ MVMFixKeyHashTable *hashtable) { | |
+ struct MVMFixKeyHashTableControl *control = hashtable->table; | |
+ MVMFixKeyHashIterator iterator; | |
+ | |
+ if (!control) { | |
+ /* This hash has not even been built yet. We return an iterator that is | |
+ * already "at the end" */ | |
+#if HASH_DEBUG_ITER | |
+ iterator.owner = iterator.serial = 0; | |
+#endif | |
+ iterator.pos = 0; | |
+ return iterator; | |
+ } | |
+ | |
+#if HASH_DEBUG_ITER | |
+ iterator.owner = control->ht_id; | |
+ iterator.serial = control->serial; | |
+#endif | |
+ | |
+ if (control->cur_items == 0) { | |
+ /* The hash is empty. No need to do the work to find the "first" item | |
+ * when we know that there are none. Return an iterator at the end. */ | |
+ iterator.pos = 0; | |
+ return iterator; | |
+ } | |
+ | |
+ iterator.pos = MVM_fixkey_hash_kompromat(control); | |
+ | |
+ if (MVM_fixkey_hash_metadata(control)[iterator.pos - 1]) { | |
+ return iterator; | |
+ } | |
+ return MVM_fixkey_hash_next(tc, hashtable, iterator); | |
+} | |
+ | |
+MVM_STATIC_INLINE MVMFixKeyHashIterator MVM_fixkey_hash_start(MVMThreadContext *tc, | |
+ MVMFixKeyHashTable *hashtable) { | |
+ struct MVMFixKeyHashTableControl *control = hashtable->table; | |
+ MVMFixKeyHashIterator retval; | |
+ if (MVM_UNLIKELY(!control)) { | |
+#if HASH_DEBUG_ITER | |
+ retval.owner = retval.serial = 0; | |
+#endif | |
+ retval.pos = 1; | |
+ return retval; | |
+ } | |
+ | |
+#if HASH_DEBUG_ITER | |
+ retval.owner = control->ht_id; | |
+ retval.serial = control->serial; | |
+#endif | |
+ retval.pos = MVM_fixkey_hash_kompromat(control) + 1; | |
+ return retval; | |
+} | |
+ | |
+MVM_STATIC_INLINE int MVM_fixkey_hash_at_start(MVMThreadContext *tc, | |
+ MVMFixKeyHashTable *hashtable, | |
+ MVMFixKeyHashIterator iterator) { | |
+ struct MVMFixKeyHashTableControl *control = hashtable->table; | |
+ if (MVM_UNLIKELY(!control)) { | |
+ return iterator.pos == 1; | |
+ } | |
+#if HASH_DEBUG_ITER | |
+ if (iterator.owner != control->ht_id) { | |
+ MVM_oops(tc, "MVM_fixkey_hash_at_start called with an iterator from a different hash table: %016" PRIx64 " != %016" PRIx64, | |
+ iterator.owner, control->ht_id); | |
+ } | |
+ if (iterator.serial != control->serial) { | |
+ MVM_oops(tc, "MVM_fixkey_hash_at_start called with an iterator with the wrong serial number: %u != %u", | |
+ iterator.serial, control->serial); | |
+ } | |
+#endif | |
+ return iterator.pos == MVM_fixkey_hash_kompromat(control) + 1; | |
+} | |
+ | |
+/* Only call this if MVM_fixkey_hash_at_end returns false. */ | |
+MVM_STATIC_INLINE void *MVM_fixkey_hash_current_nocheck(MVMThreadContext *tc, | |
+ MVMFixKeyHashTable *hashtable, | |
+ MVMFixKeyHashIterator iterator) { | |
+ struct MVMFixKeyHashTableControl *control = hashtable->table; | |
+ assert(MVM_fixkey_hash_metadata(control)[iterator.pos - 1]); | |
+ return MVM_fixkey_hash_entries(control) - control->entry_size * (iterator.pos - 1); | |
+} | |
+ | |
+/* FIXME - this needs a better name: */ | |
+MVM_STATIC_INLINE void *MVM_fixkey_hash_current(MVMThreadContext *tc, | |
+ MVMFixKeyHashTable *hashtable, | |
+ MVMFixKeyHashIterator iterator) { | |
+#if HASH_DEBUG_ITER | |
+ const struct MVMFixKeyHashTableControl *control = hashtable->table; | |
+ if (iterator.owner != control->ht_id) { | |
+ MVM_oops(tc, "MVM_fixkey_hash_current called with an iterator from a different hash table: %016" PRIx64 " != %016" PRIx64, | |
+ iterator.owner, control->ht_id); | |
+ } | |
+ if (iterator.serial != control->serial) { | |
+ MVM_oops(tc, "MVM_fixkey_hash_current called with an iterator with the wrong serial number: %u != %u", | |
+ iterator.serial, control->serial); | |
+ } | |
+#endif | |
+ | |
+ /* This is MVM_fixkey_hash_at_end without the HASH_DEBUG_ITER checks duplicated. */ | |
+ if (MVM_UNLIKELY(iterator.pos == 0)) { | |
+ /* Bother. This seems to be part of our de-facto API. */ | |
+ return NULL; | |
+ } | |
+ | |
+ return MVM_fixkey_hash_current_nocheck(tc, hashtable, iterator); | |
+} | |
diff --git src/moar.c src/moar.c | |
index 5c9ffd439..76f2a2405 100644 | |
--- src/moar.c | |
+++ src/moar.c | |
@@ -170,7 +170,7 @@ MVMInstance * MVM_vm_create_instance(void) { | |
MVM_fixkey_hash_build(instance->main_thread, &instance->compilee_hll_configs, sizeof(MVMHLLConfig)); | |
/* Set up DLL registry mutex. */ | |
- init_mutex(instance->mutex_dll_registry, "REPR registry"); | |
+ init_mutex(instance->mutex_dll_registry, "DLL registry"); | |
MVM_fixkey_hash_build(instance->main_thread, &instance->dll_registry, sizeof(struct MVMDLLRegistry)); | |
/* Set up extension registry mutex. */ | |
@@ -632,6 +632,26 @@ static void cleanup_callsite_interns(MVMInstance *instance) { | |
* short of this goal at the moment. */ | |
void MVM_vm_destroy_instance(MVMInstance *instance) { | |
+ /* Clean up Hash of DLLs. */ | |
+ /* | |
+ uv_mutex_lock(&instance->mutex_dll_registry); | |
+ MVMFixKeyHashTable *const dll_registry = &instance->dll_registry; | |
+ MVMFixKeyHashIterator iterator = MVM_fixkey_hash_first(instance->main_thread, dll_registry); | |
+ while (!MVM_fixkey_hash_at_end(instance->main_thread, dll_registry, iterator)) { | |
+ fprintf(stderr, "freeing a dll\n"); | |
+ MVMDLLRegistry *entry = MVM_fixkey_hash_current_nocheck(instance->main_thread, dll_registry, iterator); | |
+ //MVMDLLRegistry *entry = MVM_fixkey_hash_fetch_nocheck(instance->main_thread, dll_registry, name); | |
+ if (entry && entry->lib) { | |
+ fprintf(stderr, "for realz\n"); | |
+ MVM_nativecall_free_lib(entry->lib); | |
+ } | |
+ iterator = MVM_fixkey_hash_next_nocheck(instance->main_thread, dll_registry, iterator); | |
+ } | |
+ uv_mutex_unlock(&instance->mutex_dll_registry); | |
+ uv_mutex_destroy(&instance->mutex_dll_registry); | |
+ MVM_fixkey_hash_demolish(instance->main_thread, &instance->dll_registry); | |
+ */ | |
+ | |
/* Join any foreground threads and flush standard handles. */ | |
MVM_thread_join_foreground(instance->main_thread); | |
MVM_io_flush_standard_handles(instance->main_thread); | |
@@ -678,10 +698,6 @@ void MVM_vm_destroy_instance(MVMInstance *instance) { | |
MVM_fixkey_hash_demolish(instance->main_thread, &instance->compiler_hll_configs); | |
MVM_fixkey_hash_demolish(instance->main_thread, &instance->compilee_hll_configs); | |
- /* Clean up Hash of DLLs. */ | |
- uv_mutex_destroy(&instance->mutex_dll_registry); | |
- MVM_fixkey_hash_demolish(instance->main_thread, &instance->dll_registry); | |
- | |
/* Clean up Hash of extensions. */ | |
uv_mutex_destroy(&instance->mutex_ext_registry); | |
MVM_fixkey_hash_demolish(instance->main_thread, &instance->ext_registry); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment