[InstCombine] Signed saturation patterns
[llvm-core.git] / lib / Support / Windows / DynamicLibrary.inc
blob71b206c4cf9ee6e3680f5b9b532f1c7afeb0e485
1 //===- Win32/DynamicLibrary.cpp - Win32 DL Implementation -------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file provides the Win32 specific implementation of DynamicLibrary.
11 //===----------------------------------------------------------------------===//
13 #include "WindowsSupport.h"
14 #include "llvm/Support/ConvertUTF.h"
15 #include "llvm/Support/raw_ostream.h"
17 #include <psapi.h>
19 //===----------------------------------------------------------------------===//
20 //=== WARNING: Implementation here must contain only Win32 specific code
21 //===          and must not be UNIX code.
22 //===----------------------------------------------------------------------===//
25 DynamicLibrary::HandleSet::~HandleSet() {
26   for (void *Handle : llvm::reverse(Handles))
27     FreeLibrary(HMODULE(Handle));
29   // 'Process' should not be released on Windows.
30   assert((!Process || Process==this) && "Bad Handle");
31   // llvm_shutdown called, Return to default
32   DynamicLibrary::SearchOrder = DynamicLibrary::SO_Linker;
35 void *DynamicLibrary::HandleSet::DLOpen(const char *File, std::string *Err) {
36   // Create the instance and return it to be the *Process* handle
37   // simillar to dlopen(NULL, RTLD_LAZY|RTLD_GLOBAL)
38   if (!File)
39     return &(*OpenedHandles);
41   SmallVector<wchar_t, MAX_PATH> FileUnicode;
42   if (std::error_code ec = windows::UTF8ToUTF16(File, FileUnicode)) {
43     SetLastError(ec.value());
44     MakeErrMsg(Err, std::string(File) + ": Can't convert to UTF-16");
45     return &DynamicLibrary::Invalid;
46   }
48   HMODULE Handle = LoadLibraryW(FileUnicode.data());
49   if (Handle == NULL) {
50     MakeErrMsg(Err, std::string(File) + ": Can't open");
51     return &DynamicLibrary::Invalid;
52   }
54   return reinterpret_cast<void*>(Handle);
57 static DynamicLibrary::HandleSet *IsOpenedHandlesInstance(void *Handle) {
58   if (!OpenedHandles.isConstructed())
59     return nullptr;
60   DynamicLibrary::HandleSet &Inst = *OpenedHandles;
61   return Handle == &Inst ? &Inst : nullptr;
64 void DynamicLibrary::HandleSet::DLClose(void *Handle) {
65   if (HandleSet* HS = IsOpenedHandlesInstance(Handle))
66     HS->Process = nullptr; // Just drop the *Process* handle.
67   else
68     FreeLibrary((HMODULE)Handle);
71 static bool GetProcessModules(HANDLE H, DWORD &Bytes, HMODULE *Data = nullptr) {
72   // EnumProcessModules will fail on Windows 64 while some versions of
73   // MingW-32 don't have EnumProcessModulesEx.
74   if (
75 #ifdef _WIN64
76       !EnumProcessModulesEx(H, Data, Bytes, &Bytes, LIST_MODULES_64BIT)
77 #else
78       !EnumProcessModules(H, Data, Bytes, &Bytes)
79 #endif
80      ) {
81     std::string Err;
82     if (MakeErrMsg(&Err, "EnumProcessModules failure"))
83       llvm::errs() << Err << "\n";
84     return false;
85   }
86   return true;
89 void *DynamicLibrary::HandleSet::DLSym(void *Handle, const char *Symbol) {
90   HandleSet* HS = IsOpenedHandlesInstance(Handle);
91   if (!HS)
92     return (void *)uintptr_t(GetProcAddress((HMODULE)Handle, Symbol));
94   // Could have done a dlclose on the *Process* handle
95   if (!HS->Process)
96     return nullptr;
98   // Trials indicate EnumProcessModulesEx is consistantly faster than using
99   // EnumerateLoadedModules64 or CreateToolhelp32Snapshot.
100   //
101   // | Handles | DbgHelp.dll | CreateSnapshot | EnumProcessModulesEx
102   // |=========|=============|========================================
103   // | 37      | 0.0000585 * | 0.0003031      | 0.0000152
104   // | 1020    | 0.0026310 * | 0.0121598      | 0.0002683
105   // | 2084    | 0.0149418 * | 0.0369936      | 0.0005610
106   //
107   // * Not including the load time of Dbghelp.dll (~.005 sec)
108   //
109   // There's still a case to somehow cache the result of EnumProcessModulesEx
110   // across invocations, but the complication of doing that properly...
111   // Possibly using LdrRegisterDllNotification to invalidate the cache?
113   DWORD Bytes = 0;
114   HMODULE Self = HMODULE(GetCurrentProcess());
115   if (!GetProcessModules(Self, Bytes))
116     return nullptr;
118   // Get the most recent list in case any modules added/removed between calls
119   // to EnumProcessModulesEx that gets the amount of, then copies the HMODULES.
120   // MSDN is pretty clear that if the module list changes during the call to
121   // EnumProcessModulesEx the results should not be used.
122   std::vector<HMODULE> Handles;
123   do {
124     assert(Bytes && ((Bytes % sizeof(HMODULE)) == 0) &&
125            "Should have at least one module and be aligned");
126     Handles.resize(Bytes / sizeof(HMODULE));
127     if (!GetProcessModules(Self, Bytes, Handles.data()))
128       return nullptr;
129   } while (Bytes != (Handles.size() * sizeof(HMODULE)));
131   // Try EXE first, mirroring what dlsym(dlopen(NULL)) does.
132   if (FARPROC Ptr = GetProcAddress(HMODULE(Handles.front()), Symbol))
133     return (void *) uintptr_t(Ptr);
135   if (Handles.size() > 1) {
136     // This is different behaviour than what Posix dlsym(dlopen(NULL)) does.
137     // Doing that here is causing real problems for the JIT where msvc.dll
138     // and ucrt.dll can define the same symbols. The runtime linker will choose
139     // symbols from ucrt.dll first, but iterating NOT in reverse here would
140     // mean that the msvc.dll versions would be returned.
142     for (auto I = Handles.rbegin(), E = Handles.rend()-1; I != E; ++I) {
143       if (FARPROC Ptr = GetProcAddress(HMODULE(*I), Symbol))
144         return (void *) uintptr_t(Ptr);
145     }
146   }
147   return nullptr;
151 // Stack probing routines are in the support library (e.g. libgcc), but we don't
152 // have dynamic linking on windows. Provide a hook.
153 #define EXPLICIT_SYMBOL(SYM)                    \
154   extern "C" { extern void *SYM; }
155 #define EXPLICIT_SYMBOL2(SYMFROM, SYMTO) EXPLICIT_SYMBOL(SYMTO)
157 #ifdef _M_IX86
158 // Win32 on x86 implements certain single-precision math functions as macros.
159 // These functions are not exported by the DLL, but will still be needed
160 // for symbol-resolution by the JIT loader. Therefore, this Support libray
161 // provides helper functions with the same implementation.
163 #define INLINE_DEF_SYMBOL1(TYP, SYM)                                           \
164   extern "C" TYP inline_##SYM(TYP _X) { return SYM(_X); }
165 #define INLINE_DEF_SYMBOL2(TYP, SYM)                                           \
166   extern "C" TYP inline_##SYM(TYP _X, TYP _Y) { return SYM(_X, _Y); }
167 #endif
169 #include "explicit_symbols.inc"
171 #undef EXPLICIT_SYMBOL
172 #undef EXPLICIT_SYMBOL2
173 #undef INLINE_DEF_SYMBOL1
174 #undef INLINE_DEF_SYMBOL2
176 static void *DoSearch(const char *SymbolName) {
178 #define EXPLICIT_SYMBOL(SYM)                                                   \
179   if (!strcmp(SymbolName, #SYM))                                               \
180     return (void *)&SYM;
181 #define EXPLICIT_SYMBOL2(SYMFROM, SYMTO)                                       \
182   if (!strcmp(SymbolName, #SYMFROM))                                           \
183     return (void *)&SYMTO;
185 #ifdef _M_IX86
186 #define INLINE_DEF_SYMBOL1(TYP, SYM)                                           \
187   if (!strcmp(SymbolName, #SYM))                                               \
188     return (void *)&inline_##SYM;
189 #define INLINE_DEF_SYMBOL2(TYP, SYM) INLINE_DEF_SYMBOL1(TYP, SYM)
190 #endif
192   {
193 #include "explicit_symbols.inc"
194   }
196 #undef EXPLICIT_SYMBOL
197 #undef EXPLICIT_SYMBOL2
198 #undef INLINE_DEF_SYMBOL1
199 #undef INLINE_DEF_SYMBOL2
201   return nullptr;