Ben Gamari pushed to branch wip/T26009 at Glasgow Haskell Compiler / GHC
Commits:
-
827961b9
by Ben Gamari at 2025-05-19T16:01:12-04:00
-
deadc2ef
by Ben Gamari at 2025-05-19T16:01:24-04:00
3 changed files:
Changes:
... | ... | @@ -94,13 +94,13 @@ hashWord(const HashTable *table, StgWord key) |
94 | 94 | }
|
95 | 95 | |
96 | 96 | int
|
97 | -hashStr(const HashTable *table, StgWord w)
|
|
97 | +hashBuffer(const HashTable *table, const void *buf, size_t len)
|
|
98 | 98 | {
|
99 | - const char *key = (char*) w;
|
|
99 | + const char *key = (char*) buf;
|
|
100 | 100 | #if WORD_SIZE_IN_BITS == 64
|
101 | - StgWord h = XXH3_64bits_withSeed (key, strlen(key), 1048583);
|
|
101 | + StgWord h = XXH3_64bits_withSeed (key, len, 1048583);
|
|
102 | 102 | #else
|
103 | - StgWord h = XXH32 (key, strlen(key), 1048583);
|
|
103 | + StgWord h = XXH32 (key, len, 1048583);
|
|
104 | 104 | #endif
|
105 | 105 | |
106 | 106 | /* Mod the size of the hash table (a power of 2) */
|
... | ... | @@ -114,6 +114,13 @@ hashStr(const HashTable *table, StgWord w) |
114 | 114 | return bucket;
|
115 | 115 | }
|
116 | 116 | |
117 | +int
|
|
118 | +hashStr(const HashTable *table, StgWord w)
|
|
119 | +{
|
|
120 | + const char *key = (char*) w;
|
|
121 | + return hashBuffer(table, key, strlen(key));
|
|
122 | +}
|
|
123 | + |
|
117 | 124 | STATIC_INLINE int
|
118 | 125 | compareWord(StgWord key1, StgWord key2)
|
119 | 126 | {
|
... | ... | @@ -69,6 +69,10 @@ void * removeStrHashTable ( StrHashTable *table, const char * key, |
69 | 69 | */
|
70 | 70 | typedef int HashFunction(const HashTable *table, StgWord key);
|
71 | 71 | typedef int CompareFunction(StgWord key1, StgWord key2);
|
72 | + |
|
73 | +// Helper for implementing hash functions
|
|
74 | +int hashBuffer(const HashTable *table, const void *buf, size_t len);
|
|
75 | + |
|
72 | 76 | int hashWord(const HashTable *table, StgWord key);
|
73 | 77 | int hashStr(const HashTable *table, StgWord w);
|
74 | 78 | void insertHashTable_ ( HashTable *table, StgWord key,
|
... | ... | @@ -79,6 +83,7 @@ void * removeHashTable_ ( HashTable *table, StgWord key, |
79 | 83 | const void *data, HashFunction f,
|
80 | 84 | CompareFunction cmp );
|
81 | 85 | |
86 | + |
|
82 | 87 | /* Freeing hash tables
|
83 | 88 | */
|
84 | 89 | void freeHashTable ( HashTable *table, void (*freeDataFun)(void *) );
|
... | ... | @@ -427,8 +427,53 @@ const int default_alignment = 8; |
427 | 427 | the pointer as a redirect. Essentially it's a DATA DLL reference. */
|
428 | 428 | const void* __rts_iob_func = (void*)&__acrt_iob_func;
|
429 | 429 | |
430 | +/*
|
|
431 | + * Note [Avoiding repeated DLL loading]
|
|
432 | + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
433 | + * As LoadLibraryEx tends to be expensive and addDLL_PEi386 is called on every
|
|
434 | + * DLL-imported symbol, we use a hash-set to keep track of which DLLs have
|
|
435 | + * already been loaded. This hash-set is keyed on the dll_name passed to
|
|
436 | + * addDLL_PEi386 and serves as a quick check to avoid repeated calls to
|
|
437 | + * LoadLibraryEx for the identical DLL. See #26009.
|
|
438 | + */
|
|
439 | + |
|
440 | +typedef struct {
|
|
441 | + HashTable *hash;
|
|
442 | +} LoadedDllSet;
|
|
443 | + |
|
444 | +LoadedDllSet loaded_dll_set;
|
|
445 | + |
|
446 | +void initLoadedDllSet(LoadedDllSet *set) {
|
|
447 | + set->hash = allocHashTable();
|
|
448 | +}
|
|
449 | + |
|
450 | +int hash_path(const HashTable *table, StgWord w)
|
|
451 | +{
|
|
452 | + const pathchar *key = (pathchar*) w;
|
|
453 | + return hashBuffer(table, key, sizeof(pathchar) * wcslen(key));
|
|
454 | +}
|
|
455 | + |
|
456 | +int compare_path(StgWord key1, StgWord key2)
|
|
457 | +{
|
|
458 | + return wscmp((pathchar*) key1, (pathchar*) key2);
|
|
459 | +}
|
|
460 | + |
|
461 | +void addLoadedDll(LoadedDllSet *set, pathchar *dll_name)
|
|
462 | +{
|
|
463 | + insertHashTable_(set->hash, (StgWord) dll_name, (void*) 1, hash_path);
|
|
464 | +}
|
|
465 | + |
|
466 | +bool isDllLoaded(LoadedDllSet *set, pathchar *dll_name)
|
|
467 | +{
|
|
468 | + void * result = lookupHashTable_(set->hash, (StgWord) dll_name, hash_path, compare_path);
|
|
469 | + return result != NULL;
|
|
470 | +}
|
|
471 | + |
|
472 | + |
|
430 | 473 | void initLinker_PEi386(void)
|
431 | 474 | {
|
475 | + initLoadedDllSet(&loaded_dll_set);
|
|
476 | + |
|
432 | 477 | if (!ghciInsertSymbolTable(WSTR("(GHCi/Ld special symbols)"),
|
433 | 478 | symhash, "__image_base__",
|
434 | 479 | GetModuleHandleW (NULL), HS_BOOL_TRUE,
|
... | ... | @@ -802,6 +847,10 @@ addDLL_PEi386( pathchar *dll_name, HINSTANCE *loaded ) |
802 | 847 | /* ------------------- Win32 DLL loader ------------------- */
|
803 | 848 | IF_DEBUG(linker, debugBelch("addDLL; dll_name = `%" PATH_FMT "'\n", dll_name));
|
804 | 849 | |
850 | + if (isDllLoaded(&loaded_dll_set, dll_name)) {
|
|
851 | + return NULL;
|
|
852 | + }
|
|
853 | + |
|
805 | 854 | /* The file name has no suffix (yet) so that we can try
|
806 | 855 | both foo.dll and foo.drv
|
807 | 856 | |
... | ... | @@ -840,6 +889,7 @@ addDLL_PEi386( pathchar *dll_name, HINSTANCE *loaded ) |
840 | 889 | goto error;
|
841 | 890 | }
|
842 | 891 | |
892 | + addLoadedDll(&loaded_dll_set, dll_name);
|
|
843 | 893 | addDLLHandle(buf, instance);
|
844 | 894 | if (loaded) {
|
845 | 895 | *loaded = instance;
|