... |
... |
@@ -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 key)
|
|
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;
|