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;
|