1 | // Licensed to the .NET Foundation under one or more agreements. |
2 | // The .NET Foundation licenses this file to you under the MIT license. |
3 | // See the LICENSE file in the project root for more information. |
4 | |
5 | #ifndef ZAPPER_H_ |
6 | #define ZAPPER_H_ |
7 | |
8 | #include <winwrap.h> |
9 | #include <windows.h> |
10 | #include <stdlib.h> |
11 | #include <objbase.h> |
12 | #include <stddef.h> |
13 | #include <float.h> |
14 | #include <limits.h> |
15 | |
16 | #include "sarray.h" |
17 | #include "sstring.h" |
18 | #include "shash.h" |
19 | #include "utilcode.h" |
20 | #include "corjit.h" |
21 | #include "corcompile.h" |
22 | #include "corhlprpriv.h" |
23 | #include "ngen.h" |
24 | #include "corbbtprof.h" |
25 | #include "pedecoder.h" |
26 | #include "mscorsvc.h" |
27 | #include "holderinst.h" |
28 | #include "corpriv.h" |
29 | |
30 | // For side by side issues, it's best to use the exported API calls to generate a |
31 | // Zapper Object instead of creating one on your own. |
32 | |
33 | STDAPI NGenCreateNGenWorker(ICorSvcWorker **pCorSvcWorker, ILocalServerLifetime *pLocalServerLifetime, ICorSvcLogger *pCorSvcLogger); |
34 | STDAPI NGenCreateZapper(HANDLE* hZapper, NGenOptions* opt); |
35 | STDAPI NGenFreeZapper(HANDLE hZapper); |
36 | STDAPI NGenTryEnumerateFusionCache(HANDLE hZapper, LPCWSTR assemblyName, bool fPrint, bool fDelete); |
37 | STDAPI_(BOOL) NGenCompile(HANDLE hZapper, LPCWSTR path); |
38 | |
39 | |
40 | /* --------------------------------------------------------------------------- * |
41 | * Zapper classes |
42 | * --------------------------------------------------------------------------- */ |
43 | |
44 | class ZapperOptions; |
45 | class ZapperAttributionStats; |
46 | class ZapImage; |
47 | class ZapInfo; |
48 | |
49 | typedef enum CorZapLogLevel |
50 | { |
51 | CORZAP_LOGLEVEL_ERROR, |
52 | CORZAP_LOGLEVEL_WARNING, |
53 | CORZAP_LOGLEVEL_SUCCESS, |
54 | CORZAP_LOGLEVEL_INFO, |
55 | } CorZapLogLevel; |
56 | |
57 | class Zapper |
58 | { |
59 | friend class ZapImage; |
60 | friend class ZapInfo; |
61 | friend class ZapILMetaData; |
62 | |
63 | private: |
64 | |
65 | // |
66 | // Interfaces |
67 | // |
68 | |
69 | ICorDynamicInfo *m_pEEJitInfo; |
70 | ICorCompileInfo *m_pEECompileInfo; |
71 | ICorJitCompiler *m_pJitCompiler; |
72 | IMetaDataDispenserEx *m_pMetaDataDispenser; |
73 | HMODULE m_hJitLib; |
74 | #ifdef _TARGET_AMD64_ |
75 | HMODULE m_hJitLegacy; |
76 | #endif |
77 | |
78 | #ifdef ALLOW_SXS_JIT_NGEN |
79 | ICorJitCompiler *m_alternateJit; |
80 | HMODULE m_hAltJITCompiler; |
81 | #endif // ALLOW_SXS_JIT_NGEN |
82 | |
83 | // |
84 | // Options |
85 | // |
86 | |
87 | ZapperOptions * m_pOpt; |
88 | BOOL m_fFreeZapperOptions; |
89 | |
90 | SString m_exeName; // If an EXE is specified |
91 | |
92 | bool m_fromDllHost; |
93 | |
94 | // |
95 | // Current assembly info |
96 | // |
97 | |
98 | ICorCompilationDomain *m_pDomain; |
99 | CORINFO_ASSEMBLY_HANDLE m_hAssembly; |
100 | IMDInternalImport *m_pAssemblyImport; |
101 | |
102 | SString m_outputPath; // Temp folder for creating the output file |
103 | |
104 | IMetaDataAssemblyEmit *m_pAssemblyEmit; |
105 | IMetaDataAssemblyEmit *CreateAssemblyEmitter(); |
106 | |
107 | // |
108 | // |
109 | // Status info |
110 | // |
111 | |
112 | BOOL m_failed; |
113 | CorInfoRegionKind m_currentRegionKind; |
114 | |
115 | SString m_platformAssembliesPaths; |
116 | SString m_trustedPlatformAssemblies; |
117 | SString m_platformResourceRoots; |
118 | SString m_appPaths; |
119 | SString m_appNiPaths; |
120 | SString m_platformWinmdPaths; |
121 | |
122 | #if !defined(FEATURE_MERGE_JIT_AND_ENGINE) |
123 | SString m_CLRJITPath; |
124 | bool m_fDontLoadJit; |
125 | #endif // !defined(FEATURE_MERGE_JIT_AND_ENGINE) |
126 | #if !defined(NO_NGENPDB) |
127 | SString m_DiasymreaderPath; |
128 | #endif // !defined(NO_NGENPDB) |
129 | |
130 | SString m_outputFilename; |
131 | |
132 | public: |
133 | |
134 | struct assemblyDependencies |
135 | { |
136 | struct DependencyEntry |
137 | { |
138 | BSTR bstr; |
139 | LoadHintEnum loadHint; |
140 | NGenHintEnum ngenHint; |
141 | }; |
142 | |
143 | SArray<DependencyEntry> dependencyArray; |
144 | NGenHintEnum ngenHint; |
145 | SString displayName; |
146 | |
147 | assemblyDependencies() |
148 | { |
149 | Initialize(); |
150 | ngenHint = NGenDefault; |
151 | } |
152 | |
153 | ~assemblyDependencies() |
154 | { |
155 | Cleanup(); |
156 | } |
157 | |
158 | void Reinitialize() |
159 | { |
160 | Cleanup(); |
161 | Initialize(); |
162 | } |
163 | |
164 | void SetNGenHint(NGenHintEnum ngenHint) |
165 | { |
166 | this->ngenHint = ngenHint; |
167 | } |
168 | |
169 | NGenHintEnum GetNGenHint() |
170 | { |
171 | return ngenHint; |
172 | } |
173 | |
174 | void SetDisplayName(const WCHAR *pStr) |
175 | { |
176 | displayName.Set(pStr); |
177 | } |
178 | |
179 | const WCHAR *GetDisplayName() |
180 | { |
181 | return displayName.GetUnicode(); |
182 | } |
183 | |
184 | void Append(const WCHAR *pStr, LoadHintEnum loadHint = LoadDefault, NGenHintEnum ngenHint = NGenDefault) |
185 | { |
186 | // Don't append string if it's a duplicate |
187 | for (COUNT_T i = 0; i < dependencyArray.GetCount(); i++) |
188 | { |
189 | if (wcscmp(dependencyArray[i].bstr, pStr) == 0) |
190 | return; |
191 | } |
192 | |
193 | BSTRHolder bstr(::SysAllocString(pStr)); |
194 | DependencyEntry dependencyEntry; |
195 | dependencyEntry.bstr = bstr.GetValue(); |
196 | dependencyEntry.loadHint = loadHint; |
197 | dependencyEntry.ngenHint = ngenHint; |
198 | |
199 | dependencyArray.Append(dependencyEntry); |
200 | bstr.SuppressRelease(); |
201 | } |
202 | |
203 | SAFEARRAY *GetSAFEARRAY() |
204 | { |
205 | SafeArrayHolder pDependencies(SafeArrayCreateVector(VT_BSTR, 0, dependencyArray.GetCount())); |
206 | if (pDependencies.GetValue() == NULL) ThrowLastError(); |
207 | |
208 | for (COUNT_T i = 0; i < dependencyArray.GetCount(); i++) |
209 | { |
210 | LONG indices[1]; |
211 | indices[0] = (LONG) i; |
212 | IfFailThrow(SafeArrayPutElement(pDependencies, indices, this->dependencyArray[i].bstr)); |
213 | } |
214 | |
215 | pDependencies.SuppressRelease(); |
216 | return pDependencies.GetValue(); |
217 | } |
218 | |
219 | SAFEARRAY *GetLoadHintSAFEARRAY() |
220 | { |
221 | SafeArrayHolder pSettings(SafeArrayCreateVector(VT_UI4, 0, dependencyArray.GetCount())); |
222 | if (pSettings.GetValue() == NULL) ThrowLastError(); |
223 | |
224 | for (COUNT_T i = 0; i < dependencyArray.GetCount(); i++) |
225 | { |
226 | LONG indices[1]; |
227 | indices[0] = (LONG) i; |
228 | IfFailThrow(SafeArrayPutElement(pSettings, indices, &this->dependencyArray[i].loadHint)); |
229 | } |
230 | |
231 | pSettings.SuppressRelease(); |
232 | return pSettings.GetValue(); |
233 | } |
234 | |
235 | SAFEARRAY *GetNGenHintSAFEARRAY() |
236 | { |
237 | SafeArrayHolder pSettings(SafeArrayCreateVector(VT_UI4, 0, dependencyArray.GetCount())); |
238 | if (pSettings.GetValue() == NULL) ThrowLastError(); |
239 | |
240 | for (COUNT_T i = 0; i < dependencyArray.GetCount(); i++) |
241 | { |
242 | LONG indices[1]; |
243 | indices[0] = (LONG) i; |
244 | IfFailThrow(SafeArrayPutElement(pSettings, indices, &this->dependencyArray[i].ngenHint)); |
245 | } |
246 | |
247 | pSettings.SuppressRelease(); |
248 | return pSettings.GetValue(); |
249 | } |
250 | |
251 | private: |
252 | void Initialize() |
253 | { |
254 | dependencyArray.SetCount(0); |
255 | // Should we reinitialize ngenHint to the default value as well? |
256 | } |
257 | |
258 | void Cleanup() |
259 | { |
260 | for (COUNT_T i = 0; i < dependencyArray.GetCount(); i++) |
261 | { |
262 | ::SysFreeString(dependencyArray[i].bstr); |
263 | } |
264 | } |
265 | } m_assemblyDependencies; |
266 | |
267 | |
268 | public: |
269 | |
270 | Zapper(ZapperOptions *pOpt); |
271 | Zapper(NGenOptions *pOpt, bool fromDllHost = false); |
272 | |
273 | void Init(ZapperOptions *pOpt, bool fFreeZapperOptions= false); |
274 | |
275 | static Zapper *NewZapper(NGenOptions *pOpt, bool fromDllHost = false) |
276 | { |
277 | CONTRACTL |
278 | { |
279 | THROWS; |
280 | GC_NOTRIGGER; |
281 | } |
282 | CONTRACTL_END; |
283 | return new Zapper(pOpt, fromDllHost); |
284 | } |
285 | |
286 | ~Zapper(); |
287 | |
288 | // The arguments control which native image of mscorlib to use. |
289 | // This matters for hardbinding. |
290 | void InitEE(BOOL fForceDebug, BOOL fForceProfile, BOOL fForceInstrument); |
291 | void LoadAndInitializeJITForNgen(LPCWSTR pwzJitName, OUT HINSTANCE* phJit, OUT ICorJitCompiler** ppICorJitCompiler); |
292 | |
293 | |
294 | BOOL IsAssembly(LPCWSTR path); |
295 | |
296 | void CreateDependenciesLookupDomain(); |
297 | void ComputeDependencies(LPCWSTR pAssemblyName, CORCOMPILE_NGEN_SIGNATURE * pNativeImageSig); |
298 | void ComputeAssemblyDependencies(CORINFO_ASSEMBLY_HANDLE hAssembly); |
299 | |
300 | void CreatePdb(BSTR pAssemblyPathOrName, BSTR pNativeImagePath, BSTR pPdbPath, BOOL pdbLines, BSTR pManagedPdbSearchPath); |
301 | void CreatePdbInCurrentDomain(BSTR pAssemblyPathOrName, BSTR pNativeImagePath, BSTR pPdbPath, BOOL pdbLines, BSTR pManagedPdbSearchPath); |
302 | |
303 | void DefineOutputAssembly(SString& strAssemblyName, ULONG * pHashAlgId); |
304 | |
305 | HRESULT Compile(LPCWSTR path, CORCOMPILE_NGEN_SIGNATURE * pNativeImageSig = NULL); |
306 | void DontUseProfileData(); |
307 | bool HasProfileData(); |
308 | |
309 | void CompileAssembly(CORCOMPILE_NGEN_SIGNATURE * pNativeImageSig); |
310 | ZapImage * CompileModule(CORINFO_MODULE_HANDLE hModule, |
311 | IMetaDataAssemblyEmit *pEmit); |
312 | void InstallCompiledAssembly(LPCWSTR szAssemblyName, LPCWSTR szNativeImagePath, HANDLE hFile, SArray<HANDLE> &hFiles); |
313 | |
314 | HRESULT GetExceptionHR(); |
315 | |
316 | void Success(LPCWSTR format, ...); |
317 | void Error(LPCWSTR format, ...); |
318 | void Warning(LPCWSTR format, ...); |
319 | void Info(LPCWSTR format, ...); |
320 | void Print(CorZapLogLevel level, LPCWSTR format, ...); |
321 | void Print(CorZapLogLevel level, LPCWSTR format, va_list args); |
322 | void PrintErrorMessage(CorZapLogLevel level, Exception *ex); |
323 | void PrintErrorMessage(CorZapLogLevel level, HRESULT hr); |
324 | |
325 | BOOL CheckAssemblyUpToDate(CORINFO_ASSEMBLY_HANDLE hAssembly, CORCOMPILE_NGEN_SIGNATURE * pNativeImageSig); |
326 | BOOL TryToInstallFromRepository(CORINFO_ASSEMBLY_HANDLE hAssembly, CORCOMPILE_NGEN_SIGNATURE * pNativeImageSig); |
327 | BOOL TryToInstallFromRepositoryDir(SString &strNativeImageDir, |
328 | SString &strSimpleName, |
329 | CORCOMPILE_NGEN_SIGNATURE *pNativeImageSig, |
330 | BOOL *pfHitMismatchedVersion, |
331 | BOOL *pfHitMismatchedDependencies, |
332 | BOOL useHardLink = FALSE); |
333 | void CopyAndInstallFromRepository(LPCWSTR lpszNativeImageDir, |
334 | LPCWSTR lpszNativeImageName, |
335 | CORCOMPILE_NGEN_SIGNATURE * pNativeImageSig, |
336 | BOOL useHardLink = FALSE); |
337 | void InstallFromRepository(LPCWSTR lpszNativeImage, |
338 | CORCOMPILE_NGEN_SIGNATURE * pNativeImageSig); |
339 | |
340 | void CopyDirectory(LPCWSTR srcPath, LPCWSTR dstPath); |
341 | void CleanDirectory(LPCWSTR path); |
342 | void TryCleanDirectory(LPCWSTR path); |
343 | static void TryCleanDirectory(Zapper * pZapper); |
344 | |
345 | void GetOutputFolder(); |
346 | |
347 | void SetPlatformAssembliesPaths(LPCWSTR pwzPlatformAssembliesPaths); |
348 | void SetTrustedPlatformAssemblies(LPCWSTR pwzTrustedPlatformAssemblies); |
349 | void SetPlatformResourceRoots(LPCWSTR pwzPlatformResourceRoots); |
350 | void SetAppPaths(LPCWSTR pwzAppPaths); |
351 | void SetAppNiPaths(LPCWSTR pwzAppNiPaths); |
352 | void SetPlatformWinmdPaths(LPCWSTR pwzPlatformWinmdPaths); |
353 | |
354 | #if !defined(FEATURE_MERGE_JIT_AND_ENGINE) |
355 | void SetCLRJITPath(LPCWSTR pwszCLRJITPath); |
356 | void SetDontLoadJit(); |
357 | #endif // !defined(FEATURE_MERGE_JIT_AND_ENGINE) |
358 | |
359 | #if !defined(NO_NGENPDB) |
360 | void SetDiasymreaderPath(LPCWSTR pwzDiasymreaderPath); |
361 | #endif // !defined(NO_NGENPDB) |
362 | |
363 | void SetOutputFilename(LPCWSTR pwszOutputFilename); |
364 | SString GetOutputFileName(); |
365 | |
366 | private: |
367 | |
368 | void DestroyDomain(); |
369 | void CleanupAssembly(); |
370 | |
371 | void CreateCompilationDomain(); |
372 | void SetContextInfo(LPCWSTR assemblyName = NULL); |
373 | |
374 | void InitializeCompilerFlags(CORCOMPILE_VERSION_INFO * pVersionInfo); |
375 | |
376 | // DomainCallback is subclassed by each method that would like to compile in a given domain |
377 | class DomainCallback |
378 | { |
379 | public: |
380 | virtual void doCallback() = NULL; |
381 | }; |
382 | |
383 | static HRESULT __stdcall GenericDomainCallback(LPVOID pvArgs); |
384 | void InvokeDomainCallback(DomainCallback *callback); |
385 | |
386 | void CompileInCurrentDomain(__in LPCWSTR path, CORCOMPILE_NGEN_SIGNATURE * pNativeImageSig); |
387 | void ComputeDependenciesInCurrentDomain(LPCWSTR pAssemblyName, CORCOMPILE_NGEN_SIGNATURE * pNativeImageSig); |
388 | void CreateDependenciesLookupDomainInCurrentDomain(); |
389 | |
390 | void HangWorker(LPCWSTR hangKey, LPCWSTR insideHangKey); |
391 | }; |
392 | |
393 | class ZapperOptions |
394 | { |
395 | public: |
396 | enum StatOptions |
397 | { |
398 | NO_STATS = 0, |
399 | DEFAULT_STATS = 1, |
400 | FIXUP_STATS = DEFAULT_STATS << 1, |
401 | CALL_STATS = FIXUP_STATS << 1, |
402 | ATTRIB_STATS = CALL_STATS << 1, |
403 | ALL_STATS = ~NO_STATS, |
404 | }; |
405 | |
406 | LPWSTR m_zapSet; // Add to zap string. Use to get a private scope of ngen images, for debugging/testing |
407 | |
408 | LPCWSTR m_repositoryDir; // Directory with prebuilt native images |
409 | RepositoryFlags m_repositoryFlags; // Copy the native images back to NativeImagesDir |
410 | |
411 | bool m_autodebug; // Use the debug setting specified by the IL module |
412 | |
413 | MethodNamesList* m_onlyMethods; // only methods to process |
414 | MethodNamesList* m_excludeMethods; // excluded these methods |
415 | mdToken m_onlyOneMethod; // only compile method with matching token |
416 | |
417 | bool m_silent; // Dont spew any text output |
418 | bool m_verbose; // Spew extra text ouput |
419 | bool m_ignoreErrors; // Continue in the face of errors |
420 | unsigned m_statOptions; // print statisitcs on number of methods, size of code ... |
421 | bool m_ngenProfileImage; // ngening with "/prof" |
422 | |
423 | // Which optimizations should be done |
424 | bool m_ignoreProfileData; // Don't use profile data |
425 | bool m_noProcedureSplitting; // Don't do procedure splitting |
426 | |
427 | bool m_fHasAnyProfileData; // true if we successfully loaded and used |
428 | // any profile data when compiling this assembly |
429 | |
430 | bool m_fPartialNGen; // Generate partial NGen images using IBC data |
431 | |
432 | bool m_fPartialNGenSet; // m_fPartialNGen has been set through the environment |
433 | |
434 | bool m_fAutoNGen; // This is an automatic NGen request |
435 | |
436 | bool m_fRepositoryOnly; // Install from repository only, no real NGen |
437 | |
438 | bool m_fNGenLastRetry; // This is retry of the compilation |
439 | |
440 | CORJIT_FLAGS m_compilerFlags; |
441 | |
442 | bool m_fNoMetaData; // Do not copy metadata and IL to native image |
443 | |
444 | void SetCompilerFlags(void); |
445 | |
446 | ZapperOptions(); |
447 | ~ZapperOptions(); |
448 | }; |
449 | |
450 | #endif // ZAPPER_H_ |
451 | |
452 | |