Ben Gamari pushed to branch wip/T26009 at Glasgow Haskell Compiler / GHC

Commits:

1 changed file:

Changes:

  • rts/linker/PEi386.c
    ... ... @@ -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-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
    +static void initLoadedDllSet(LoadedDllSet *set) {
    
    447
    +    set->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);
    
    459
    +}
    
    460
    +
    
    461
    +static void addLoadedDll(LoadedDllSet *set, pathchar *dll_name)
    
    462
    +{
    
    463
    +    insertHashTable_(set->hash, (StgWord) dll_name, (void*) 1, hash_path);
    
    464
    +}
    
    465
    +
    
    466
    +static 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
    +
    
    430 472
     void initLinker_PEi386(void)
    
    431 473
     {
    
    474
    +    initLoadedDllSet(&loaded_dll_set);
    
    475
    +
    
    432 476
         if (!ghciInsertSymbolTable(WSTR("(GHCi/Ld special symbols)"),
    
    433 477
                                    symhash, "__image_base__",
    
    434 478
                                    GetModuleHandleW (NULL), HS_BOOL_TRUE,
    
    ... ... @@ -802,6 +846,10 @@ addDLL_PEi386( pathchar *dll_name, HINSTANCE *loaded )
    802 846
         /* ------------------- Win32 DLL loader ------------------- */
    
    803 847
         IF_DEBUG(linker, debugBelch("addDLL; dll_name = `%" PATH_FMT "'\n", dll_name));
    
    804 848
     
    
    849
    +    if (isDllLoaded(&loaded_dll_set, dll_name)) {
    
    850
    +        return NULL;
    
    851
    +    }
    
    852
    +
    
    805 853
         /* The file name has no suffix (yet) so that we can try
    
    806 854
            both foo.dll and foo.drv
    
    807 855
     
    
    ... ... @@ -840,6 +888,7 @@ addDLL_PEi386( pathchar *dll_name, HINSTANCE *loaded )
    840 888
             goto error;
    
    841 889
         }
    
    842 890
     
    
    891
    +    addLoadedDll(&loaded_dll_set, dll_name);
    
    843 892
         addDLLHandle(buf, instance);
    
    844 893
         if (loaded) {
    
    845 894
             *loaded = instance;