Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save niner/93eda8852910d6f02b61ff6d18c59164 to your computer and use it in GitHub Desktop.
Save niner/93eda8852910d6f02b61ff6d18c59164 to your computer and use it in GitHub Desktop.
diff --git a/src/core/dll.c b/src/core/dll.c
index 6817b410f..83a667848 100644
--- a/src/core/dll.c
+++ b/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) {
@@ -43,11 +44,11 @@ int MVM_dll_load(MVMThreadContext *tc, MVMString *name, MVMString *path) {
entry->lib = lib;
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 a/src/core/fixkey_hash_table.h b/src/core/fixkey_hash_table.h
index 2e24be325..2290d2a4e 100644
--- a/src/core/fixkey_hash_table.h
+++ b/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 a/src/core/fixkey_hash_table_funcs.h b/src/core/fixkey_hash_table_funcs.h
index d1753f995..27efeaad9 100644
--- a/src/core/fixkey_hash_table_funcs.h
+++ b/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 a/src/moar.c b/src/moar.c
index 5c9ffd439..2e5bcde22 100644
--- a/src/moar.c
+++ b/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. */
@@ -679,6 +679,20 @@ void MVM_vm_destroy_instance(MVMInstance *instance) {
MVM_fixkey_hash_demolish(instance->main_thread, &instance->compilee_hll_configs);
/* 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);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment