... |
... |
@@ -378,7 +378,7 @@ static size_t makeSymbolExtra_PEi386( |
378
|
378
|
#endif
|
379
|
379
|
|
380
|
380
|
static void addDLLHandle(
|
381
|
|
- pathchar* dll_name,
|
|
381
|
+ const pathchar* dll_name,
|
382
|
382
|
HINSTANCE instance);
|
383
|
383
|
|
384
|
384
|
static bool verifyCOFFHeader(
|
... |
... |
@@ -427,8 +427,52 @@ 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-map to keep track of which DLLs have
|
|
435
|
+ * already been loaded. This hash-map is keyed on the dll_name passed to
|
|
436
|
+ * addDLL_PEi386 and is mapped to its HINSTANCE. This serves as a quick check
|
|
437
|
+ * to avoid repeated calls to LoadLibraryEx for the identical DLL. See #26009.
|
|
438
|
+ */
|
|
439
|
+
|
|
440
|
+typedef struct {
|
|
441
|
+ HashTable *hash;
|
|
442
|
+} LoadedDllCache;
|
|
443
|
+
|
|
444
|
+LoadedDllCache loaded_dll_cache;
|
|
445
|
+
|
|
446
|
+static void initLoadedDllCache(LoadedDllCache *cache) {
|
|
447
|
+ cache->hash = allocHashTable();
|
|
448
|
+}
|
|
449
|
+
|
|
450
|
+static 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
|
+static int compare_path(StgWord key1, StgWord key2)
|
|
457
|
+{
|
|
458
|
+ return wcscmp((pathchar*) key1, (pathchar*) key2) == 0;
|
|
459
|
+}
|
|
460
|
+
|
|
461
|
+static void addLoadedDll(LoadedDllCache *cache, const pathchar *dll_name, HINSTANCE instance)
|
|
462
|
+{
|
|
463
|
+ insertHashTable_(cache->hash, (StgWord) dll_name, instance, hash_path);
|
|
464
|
+}
|
|
465
|
+
|
|
466
|
+static HINSTANCE isDllLoaded(const LoadedDllCache *cache, const pathchar *dll_name)
|
|
467
|
+{
|
|
468
|
+ void *result = lookupHashTable_(cache->hash, (StgWord) dll_name, hash_path, compare_path);
|
|
469
|
+ return (HINSTANCE) result;
|
|
470
|
+}
|
|
471
|
+
|
430
|
472
|
void initLinker_PEi386(void)
|
431
|
473
|
{
|
|
474
|
+ initLoadedDllCache(&loaded_dll_cache);
|
|
475
|
+
|
432
|
476
|
if (!ghciInsertSymbolTable(WSTR("(GHCi/Ld special symbols)"),
|
433
|
477
|
symhash, "__image_base__",
|
434
|
478
|
GetModuleHandleW (NULL), HS_BOOL_TRUE,
|
... |
... |
@@ -455,7 +499,7 @@ void exitLinker_PEi386(void) |
455
|
499
|
static OpenedDLL* opened_dlls = NULL;
|
456
|
500
|
|
457
|
501
|
/* Adds a DLL instance to the list of DLLs in which to search for symbols. */
|
458
|
|
-static void addDLLHandle(pathchar* dll_name, HINSTANCE instance) {
|
|
502
|
+static void addDLLHandle(const pathchar* dll_name, HINSTANCE instance) {
|
459
|
503
|
|
460
|
504
|
IF_DEBUG(linker, debugBelch("addDLLHandle(%" PATH_FMT ")...\n", dll_name));
|
461
|
505
|
/* At this point, we actually know what was loaded.
|
... |
... |
@@ -797,11 +841,20 @@ uint8_t* getSymShortName ( COFF_HEADER_INFO *info, COFF_symbol* sym ) |
797
|
841
|
}
|
798
|
842
|
|
799
|
843
|
const char *
|
800
|
|
-addDLL_PEi386( pathchar *dll_name, HINSTANCE *loaded )
|
|
844
|
+addDLL_PEi386( const pathchar *dll_name, HINSTANCE *loaded )
|
801
|
845
|
{
|
802
|
846
|
/* ------------------- Win32 DLL loader ------------------- */
|
803
|
847
|
IF_DEBUG(linker, debugBelch("addDLL; dll_name = `%" PATH_FMT "'\n", dll_name));
|
804
|
848
|
|
|
849
|
+ // See Note [Avoiding repeated DLL loading]
|
|
850
|
+ HINSTANCE instance = isDllLoaded(&loaded_dll_cache, dll_name);
|
|
851
|
+ if (instance) {
|
|
852
|
+ if (loaded) {
|
|
853
|
+ *loaded = instance;
|
|
854
|
+ }
|
|
855
|
+ return NULL;
|
|
856
|
+ }
|
|
857
|
+
|
805
|
858
|
/* The file name has no suffix (yet) so that we can try
|
806
|
859
|
both foo.dll and foo.drv
|
807
|
860
|
|
... |
... |
@@ -820,7 +873,6 @@ addDLL_PEi386( pathchar *dll_name, HINSTANCE *loaded ) |
820
|
873
|
const DWORD flags[] = { LOAD_LIBRARY_SEARCH_USER_DIRS | LOAD_LIBRARY_SEARCH_DEFAULT_DIRS, 0 };
|
821
|
874
|
|
822
|
875
|
/* Iterate through the possible flags and formats. */
|
823
|
|
- HINSTANCE instance;
|
824
|
876
|
for (int cFlag = 0; cFlag < 2; cFlag++) {
|
825
|
877
|
for (int cFormat = 0; cFormat < 4; cFormat++) {
|
826
|
878
|
snwprintf(buf, bufsize, formats[cFormat], dll_name);
|
... |
... |
@@ -830,16 +882,16 @@ addDLL_PEi386( pathchar *dll_name, HINSTANCE *loaded ) |
830
|
882
|
goto error;
|
831
|
883
|
}
|
832
|
884
|
} else {
|
833
|
|
- break; /* We're done. DLL has been loaded. */
|
|
885
|
+ goto loaded; /* We're done. DLL has been loaded. */
|
834
|
886
|
}
|
835
|
887
|
}
|
836
|
888
|
}
|
837
|
889
|
|
838
|
|
- /* Check if we managed to load the DLL. */
|
839
|
|
- if (instance == NULL) {
|
840
|
|
- goto error;
|
841
|
|
- }
|
|
890
|
+ // We failed to load
|
|
891
|
+ goto error;
|
842
|
892
|
|
|
893
|
+loaded:
|
|
894
|
+ addLoadedDll(&loaded_dll_cache, dll_name, instance);
|
843
|
895
|
addDLLHandle(buf, instance);
|
844
|
896
|
if (loaded) {
|
845
|
897
|
*loaded = instance;
|