1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
5 using System.Collections.Generic;
6 using System.Collections.Immutable;
8 using System.Reflection.Metadata;
9 using System.Reflection.PortableExecutable;
10 using System.Runtime.InteropServices;
13 using Internal.CommandLine;
15 using Internal.TypeSystem;
16 using Internal.TypeSystem.Ecma;
20 internal class Program
22 private const string DefaultSystemModule = "System.Private.CoreLib";
24 private CommandLineOptions _commandLineOptions;
25 public TargetOS _targetOS;
26 public TargetArchitecture _targetArchitecture;
27 private bool _armelAbi = false;
28 public OptimizationMode _optimizationMode;
30 // File names as strings in args
31 private Dictionary<string, string> _inputFilePaths = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
32 private Dictionary<string, string> _unrootedInputFilePaths = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
33 private Dictionary<string, string> _referenceFilePaths = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
35 // Modules and their names after loading
36 private Dictionary<string, string> _allInputFilePaths = new Dictionary<string, string>();
37 private List<ModuleDesc> _referenceableModules = new List<ModuleDesc>();
39 private Dictionary<string, string> _inputbubblereferenceFilePaths = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
41 private CompilerTypeSystemContext _typeSystemContext;
42 private ReadyToRunMethodLayoutAlgorithm _methodLayout;
43 private ReadyToRunFileLayoutAlgorithm _fileLayout;
49 public static void ComputeDefaultOptions(out TargetOS os, out TargetArchitecture arch)
51 if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
52 os = TargetOS.Windows;
53 else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
55 else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
58 throw new NotImplementedException();
60 switch (RuntimeInformation.ProcessArchitecture)
62 case Architecture.X86:
63 arch = TargetArchitecture.X86;
65 case Architecture.X64:
66 arch = TargetArchitecture.X64;
68 case Architecture.Arm:
69 arch = TargetArchitecture.ARM;
71 case Architecture.Arm64:
72 arch = TargetArchitecture.ARM64;
75 throw new NotImplementedException();
80 private void InitializeDefaultOptions()
82 ComputeDefaultOptions(out _targetOS, out _targetArchitecture);
85 private void ProcessCommandLine(string[] args)
87 PerfEventSource.StartStopEvents.CommandLineProcessingStart();
88 _commandLineOptions = new CommandLineOptions(args);
89 PerfEventSource.StartStopEvents.CommandLineProcessingStop();
91 if (_commandLineOptions.Help)
96 if (_commandLineOptions.WaitForDebugger)
98 Console.WriteLine(SR.WaitingForDebuggerAttach);
102 if (_commandLineOptions.CompileBubbleGenerics)
104 if (!_commandLineOptions.CompositeOrInputBubble)
106 Console.WriteLine(SR.WarningIgnoringBubbleGenerics);
107 _commandLineOptions.CompileBubbleGenerics = false;
111 _optimizationMode = OptimizationMode.None;
112 if (_commandLineOptions.OptimizeDisabled)
114 if (_commandLineOptions.Optimize || _commandLineOptions.OptimizeSpace || _commandLineOptions.OptimizeTime)
115 Console.WriteLine(SR.WarningOverridingOptimize);
117 else if (_commandLineOptions.OptimizeSpace)
119 if (_commandLineOptions.OptimizeTime)
120 Console.WriteLine(SR.WarningOverridingOptimizeSpace);
121 _optimizationMode = OptimizationMode.PreferSize;
123 else if (_commandLineOptions.OptimizeTime)
124 _optimizationMode = OptimizationMode.PreferSpeed;
125 else if (_commandLineOptions.Optimize)
126 _optimizationMode = OptimizationMode.Blended;
128 foreach (var input in _commandLineOptions.InputFilePaths)
129 Helpers.AppendExpandedPaths(_inputFilePaths, input, true);
131 foreach (var input in _commandLineOptions.UnrootedInputFilePaths)
132 Helpers.AppendExpandedPaths(_unrootedInputFilePaths, input, true);
134 foreach (var reference in _commandLineOptions.ReferenceFilePaths)
135 Helpers.AppendExpandedPaths(_referenceFilePaths, reference, false);
137 foreach (var reference in _commandLineOptions.InputBubbleReferenceFilePaths)
138 Helpers.AppendExpandedPaths(_inputbubblereferenceFilePaths, reference, false);
141 int alignment = _commandLineOptions.CustomPESectionAlignment;
144 // Must be a power of two and >= 4096
145 if (alignment < 4096 || (alignment & (alignment - 1)) != 0)
146 throw new CommandLineException(SR.InvalidCustomPESectionAlignment);
149 if (_commandLineOptions.MethodLayout != null)
151 _methodLayout = _commandLineOptions.MethodLayout.ToLowerInvariant() switch
153 "defaultsort" => ReadyToRunMethodLayoutAlgorithm.DefaultSort,
154 "exclusiveweight" => ReadyToRunMethodLayoutAlgorithm.ExclusiveWeight,
155 "hotcold" => ReadyToRunMethodLayoutAlgorithm.HotCold,
156 "hotwarmcold" => ReadyToRunMethodLayoutAlgorithm.HotWarmCold,
157 "callfrequency" => ReadyToRunMethodLayoutAlgorithm.CallFrequency,
158 "pettishansen" => ReadyToRunMethodLayoutAlgorithm.PettisHansen,
159 "random" => ReadyToRunMethodLayoutAlgorithm.Random,
160 _ => throw new CommandLineException(SR.InvalidMethodLayout)
164 if (_commandLineOptions.FileLayout != null)
166 _fileLayout = _commandLineOptions.FileLayout.ToLowerInvariant() switch
168 "defaultsort" => ReadyToRunFileLayoutAlgorithm.DefaultSort,
169 "methodorder" => ReadyToRunFileLayoutAlgorithm.MethodOrder,
170 _ => throw new CommandLineException(SR.InvalidFileLayout)
176 public static TargetArchitecture GetTargetArchitectureFromArg(string archArg, out bool armelAbi)
179 if (archArg.Equals("x86", StringComparison.OrdinalIgnoreCase))
180 return TargetArchitecture.X86;
181 else if (archArg.Equals("x64", StringComparison.OrdinalIgnoreCase))
182 return TargetArchitecture.X64;
183 else if (archArg.Equals("arm", StringComparison.OrdinalIgnoreCase))
184 return TargetArchitecture.ARM;
185 else if (archArg.Equals("armel", StringComparison.OrdinalIgnoreCase))
188 return TargetArchitecture.ARM;
190 else if (archArg.Equals("arm64", StringComparison.OrdinalIgnoreCase))
191 return TargetArchitecture.ARM64;
193 throw new CommandLineException(SR.TargetArchitectureUnsupported);
196 private void ConfigureTarget()
199 // Set target Architecture and OS
201 if (_commandLineOptions.TargetArch != null)
203 _targetArchitecture = GetTargetArchitectureFromArg(_commandLineOptions.TargetArch, out _armelAbi);
205 if (_commandLineOptions.TargetOS != null)
207 if (_commandLineOptions.TargetOS.Equals("windows", StringComparison.OrdinalIgnoreCase))
208 _targetOS = TargetOS.Windows;
209 else if (_commandLineOptions.TargetOS.Equals("linux", StringComparison.OrdinalIgnoreCase))
210 _targetOS = TargetOS.Linux;
211 else if (_commandLineOptions.TargetOS.Equals("osx", StringComparison.OrdinalIgnoreCase))
212 _targetOS = TargetOS.OSX;
214 throw new CommandLineException(SR.TargetOSUnsupported);
218 private InstructionSetSupport ConfigureInstructionSetSupport()
220 InstructionSetSupportBuilder instructionSetSupportBuilder = new InstructionSetSupportBuilder(_targetArchitecture);
222 // Ready to run images are built with certain instruction set baselines
223 if ((_targetArchitecture == TargetArchitecture.X86) || (_targetArchitecture == TargetArchitecture.X64))
225 instructionSetSupportBuilder.AddSupportedInstructionSet("sse");
226 instructionSetSupportBuilder.AddSupportedInstructionSet("sse2");
228 else if (_targetArchitecture == TargetArchitecture.ARM64)
230 instructionSetSupportBuilder.AddSupportedInstructionSet("base");
231 instructionSetSupportBuilder.AddSupportedInstructionSet("neon");
235 if (_commandLineOptions.InstructionSet != null)
237 List<string> instructionSetParams = new List<string>();
239 // Normalize instruction set format to include implied +.
240 string[] instructionSetParamsInput = _commandLineOptions.InstructionSet.Split(",");
241 for (int i = 0; i < instructionSetParamsInput.Length; i++)
243 string instructionSet = instructionSetParamsInput[i];
245 if (String.IsNullOrEmpty(instructionSet))
246 throw new CommandLineException(String.Format(SR.InstructionSetMustNotBe, ""));
248 char firstChar = instructionSet[0];
249 if ((firstChar != '+') && (firstChar != '-'))
251 instructionSet = "+" + instructionSet;
253 instructionSetParams.Add(instructionSet);
256 Dictionary<string, bool> instructionSetSpecification = new Dictionary<string, bool>();
257 foreach (string instructionSetSpecifier in instructionSetParams)
259 string instructionSet = instructionSetSpecifier.Substring(1, instructionSetSpecifier.Length - 1);
261 bool enabled = instructionSetSpecifier[0] == '+' ? true : false;
264 if (!instructionSetSupportBuilder.AddSupportedInstructionSet(instructionSet))
265 throw new CommandLineException(String.Format(SR.InstructionSetMustNotBe, instructionSet));
269 if (!instructionSetSupportBuilder.RemoveInstructionSetSupport(instructionSet))
270 throw new CommandLineException(String.Format(SR.InstructionSetMustNotBe, instructionSet));
275 instructionSetSupportBuilder.ComputeInstructionSetFlags(out var supportedInstructionSet, out var unsupportedInstructionSet,
276 (string specifiedInstructionSet, string impliedInstructionSet) =>
277 throw new CommandLineException(String.Format(SR.InstructionSetInvalidImplication, specifiedInstructionSet, impliedInstructionSet)));
279 InstructionSetSupportBuilder optimisticInstructionSetSupportBuilder = new InstructionSetSupportBuilder(_targetArchitecture);
281 // Ready to run images are built with certain instruction sets that are optimistically assumed to be present
282 if ((_targetArchitecture == TargetArchitecture.X86) || (_targetArchitecture == TargetArchitecture.X64))
284 // For ReadyToRun we set these hardware features as enabled always, as most
285 // of hardware in the wild supports them. Note that we do not indicate support for AVX, or any other
286 // instruction set which uses the VEX encodings as the presence of those makes otherwise acceptable
287 // code be unusable on hardware which does not support VEX encodings, as well as emulators that do not
288 // support AVX instructions. As the jit generates logic that depends on these features it will call
289 // notifyInstructionSetUsage, which will result in generation of a fixup to verify the behavior of
292 optimisticInstructionSetSupportBuilder.AddSupportedInstructionSet("sse");
293 optimisticInstructionSetSupportBuilder.AddSupportedInstructionSet("sse2");
294 optimisticInstructionSetSupportBuilder.AddSupportedInstructionSet("sse4.1");
295 optimisticInstructionSetSupportBuilder.AddSupportedInstructionSet("sse4.2");
296 optimisticInstructionSetSupportBuilder.AddSupportedInstructionSet("aes");
297 optimisticInstructionSetSupportBuilder.AddSupportedInstructionSet("pclmul");
298 optimisticInstructionSetSupportBuilder.AddSupportedInstructionSet("popcnt");
299 optimisticInstructionSetSupportBuilder.AddSupportedInstructionSet("lzcnt");
302 optimisticInstructionSetSupportBuilder.ComputeInstructionSetFlags(out var optimisticInstructionSet, out _,
303 (string specifiedInstructionSet, string impliedInstructionSet) => throw new NotSupportedException());
304 optimisticInstructionSet.Remove(unsupportedInstructionSet);
305 optimisticInstructionSet.Add(supportedInstructionSet);
307 return new InstructionSetSupport(supportedInstructionSet,
308 unsupportedInstructionSet,
309 optimisticInstructionSet,
310 InstructionSetSupportBuilder.GetNonSpecifiableInstructionSetsForArch(_targetArchitecture),
311 _targetArchitecture);
314 private int Run(string[] args)
316 InitializeDefaultOptions();
318 ProcessCommandLine(args);
320 if (_commandLineOptions.Help)
322 Console.WriteLine(_commandLineOptions.HelpText);
326 if (_commandLineOptions.OutputFilePath == null && !_commandLineOptions.OutNearInput)
327 throw new CommandLineException(SR.MissingOutputFile);
329 if (_commandLineOptions.SingleFileCompilation && !_commandLineOptions.OutNearInput)
330 throw new CommandLineException(SR.MissingOutNearInput);
333 InstructionSetSupport instructionSetSupport = ConfigureInstructionSetSupport();
335 SharedGenericsMode genericsMode = SharedGenericsMode.CanonicalReferenceTypes;
337 var targetDetails = new TargetDetails(_targetArchitecture, _targetOS, _armelAbi ? TargetAbi.CoreRTArmel : TargetAbi.CoreRT, instructionSetSupport.GetVectorTSimdVector());
339 bool versionBubbleIncludesCoreLib = false;
340 if (_commandLineOptions.InputBubble)
342 versionBubbleIncludesCoreLib = true;
346 if (!_commandLineOptions.SingleFileCompilation)
348 foreach (var inputFile in _inputFilePaths)
350 if (String.Compare(inputFile.Key, "System.Private.CoreLib", StringComparison.OrdinalIgnoreCase) == 0)
352 versionBubbleIncludesCoreLib = true;
357 if (!versionBubbleIncludesCoreLib)
359 foreach (var inputFile in _unrootedInputFilePaths)
361 if (String.Compare(inputFile.Key, "System.Private.CoreLib", StringComparison.OrdinalIgnoreCase) == 0)
363 versionBubbleIncludesCoreLib = true;
371 // Initialize type system context
373 _typeSystemContext = new ReadyToRunCompilerContext(targetDetails, genericsMode, versionBubbleIncludesCoreLib);
375 string compositeRootPath = _commandLineOptions.CompositeRootPath;
377 // Collections for already loaded modules
378 Dictionary<string, string> inputFilePaths = new Dictionary<string, string>();
379 Dictionary<string, string> unrootedInputFilePaths = new Dictionary<string, string>();
380 HashSet<ModuleDesc> versionBubbleModulesHash = new HashSet<ModuleDesc>();
382 using (PerfEventSource.StartStopEvents.LoadingEvents())
385 // TODO: To support our pre-compiled test tree, allow input files that aren't managed assemblies since
386 // some tests contain a mixture of both managed and native binaries.
388 // See: https://github.com/dotnet/corert/issues/2785
390 // When we undo this this hack, replace this foreach with
391 // typeSystemContext.InputFilePaths = inFilePaths;
394 foreach (var inputFile in _inputFilePaths)
398 var module = _typeSystemContext.GetModuleFromPath(inputFile.Value);
399 _allInputFilePaths.Add(inputFile.Key, inputFile.Value);
400 inputFilePaths.Add(inputFile.Key, inputFile.Value);
401 _referenceableModules.Add(module);
402 if (compositeRootPath == null)
404 compositeRootPath = Path.GetDirectoryName(inputFile.Value);
407 catch (TypeSystemException.BadImageFormatException)
409 // Keep calm and carry on.
413 foreach (var unrootedInputFile in _unrootedInputFilePaths)
417 var module = _typeSystemContext.GetModuleFromPath(unrootedInputFile.Value);
418 if (!_allInputFilePaths.ContainsKey(unrootedInputFile.Key))
420 _allInputFilePaths.Add(unrootedInputFile.Key, unrootedInputFile.Value);
421 unrootedInputFilePaths.Add(unrootedInputFile.Key, unrootedInputFile.Value);
422 _referenceableModules.Add(module);
423 if (compositeRootPath == null)
425 compositeRootPath = Path.GetDirectoryName(unrootedInputFile.Value);
429 catch (TypeSystemException.BadImageFormatException)
431 // Keep calm and carry on.
435 CheckManagedCppInputFiles(_allInputFilePaths.Values);
437 _typeSystemContext.InputFilePaths = _allInputFilePaths;
438 _typeSystemContext.ReferenceFilePaths = _referenceFilePaths;
440 if (_typeSystemContext.InputFilePaths.Count == 0)
442 if (_commandLineOptions.InputFilePaths.Count > 0)
444 Console.WriteLine(SR.InputWasNotLoadable);
447 throw new CommandLineException(SR.NoInputFiles);
450 foreach (var referenceFile in _referenceFilePaths.Values)
454 EcmaModule module = _typeSystemContext.GetModuleFromPath(referenceFile);
455 _referenceableModules.Add(module);
456 if (_commandLineOptions.InputBubble && _inputbubblereferenceFilePaths.Count == 0)
458 // In large version bubble mode add reference paths to the compilation group
459 // Consider bubble as large if no explicit bubble references were passed
460 versionBubbleModulesHash.Add(module);
463 catch { } // Ignore non-managed pe files
466 if (_commandLineOptions.InputBubble)
468 foreach (var referenceFile in _inputbubblereferenceFilePaths.Values)
472 EcmaModule module = _typeSystemContext.GetModuleFromPath(referenceFile);
473 versionBubbleModulesHash.Add(module);
475 catch { } // Ignore non-managed pe files
480 string systemModuleName = _commandLineOptions.SystemModule ?? DefaultSystemModule;
481 _typeSystemContext.SetSystemModule((EcmaModule)_typeSystemContext.GetModuleForSimpleName(systemModuleName));
482 CompilerTypeSystemContext typeSystemContext = _typeSystemContext;
484 if (_commandLineOptions.SingleFileCompilation)
486 var singleCompilationInputFilePaths = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
488 foreach (var inputFile in inputFilePaths)
490 var singleCompilationVersionBubbleModulesHash = new HashSet<ModuleDesc>(versionBubbleModulesHash);
492 singleCompilationInputFilePaths.Clear();
493 singleCompilationInputFilePaths.Add(inputFile.Key, inputFile.Value);
494 typeSystemContext.InputFilePaths = singleCompilationInputFilePaths;
496 if (!_commandLineOptions.InputBubble)
498 bool singleCompilationVersionBubbleIncludesCoreLib = versionBubbleIncludesCoreLib || (String.Compare(inputFile.Key, "System.Private.CoreLib", StringComparison.OrdinalIgnoreCase) == 0);
500 typeSystemContext = new ReadyToRunCompilerContext(targetDetails, genericsMode, singleCompilationVersionBubbleIncludesCoreLib, _typeSystemContext);
501 typeSystemContext.SetSystemModule((EcmaModule)typeSystemContext.GetModuleForSimpleName(systemModuleName));
504 RunSingleCompilation(singleCompilationInputFilePaths, instructionSetSupport, compositeRootPath, unrootedInputFilePaths, singleCompilationVersionBubbleModulesHash, typeSystemContext);
507 // In case of inputbubble ni.dll are created as ni.dll.tmp in order to not interfere with crossgen2, move them all to ni.dll
508 // See https://github.com/dotnet/runtime/issues/55663#issuecomment-898161751 for more details
509 if (_commandLineOptions.InputBubble)
511 foreach (var inputFile in inputFilePaths)
513 var tmpOutFile = inputFile.Value.Replace(".dll", ".ni.dll.tmp");
514 var outFile = inputFile.Value.Replace(".dll", ".ni.dll");
515 Console.WriteLine($@"Moving R2R PE file: {tmpOutFile} to {outFile}");
516 System.IO.File.Move(tmpOutFile, outFile);
522 RunSingleCompilation(inputFilePaths, instructionSetSupport, compositeRootPath, unrootedInputFilePaths, versionBubbleModulesHash, typeSystemContext);
528 private void RunSingleCompilation(Dictionary<string, string> inFilePaths, InstructionSetSupport instructionSetSupport, string compositeRootPath, Dictionary<string, string> unrootedInputFilePaths, HashSet<ModuleDesc> versionBubbleModulesHash, CompilerTypeSystemContext typeSystemContext)
531 // Initialize output filename
533 var suffixStr = _commandLineOptions.SingleFileCompilation && _commandLineOptions.InputBubble ? ".ni.dll.tmp" : ".ni.dll";
534 var outFile = _commandLineOptions.OutNearInput ? inFilePaths.First().Value.Replace(".dll", suffixStr) : _commandLineOptions.OutputFilePath;
536 using (PerfEventSource.StartStopEvents.CompilationEvents())
538 ICompilation compilation;
539 using (PerfEventSource.StartStopEvents.LoadingEvents())
542 List<EcmaModule> inputModules = new List<EcmaModule>();
543 List<EcmaModule> rootingModules = new List<EcmaModule>();
545 foreach (var inputFile in inFilePaths)
547 EcmaModule module = typeSystemContext.GetModuleFromPath(inputFile.Value);
548 inputModules.Add(module);
549 rootingModules.Add(module);
550 versionBubbleModulesHash.Add(module);
553 if (!_commandLineOptions.CompositeOrInputBubble)
559 foreach (var unrootedInputFile in unrootedInputFilePaths)
561 EcmaModule module = typeSystemContext.GetModuleFromPath(unrootedInputFile.Value);
562 inputModules.Add(module);
563 versionBubbleModulesHash.Add(module);
567 // Initialize compilation group and compilation roots
570 // Single method mode?
571 MethodDesc singleMethod = CheckAndParseSingleMethodModeArguments(typeSystemContext);
573 var logger = new Logger(Console.Out, _commandLineOptions.Verbose);
575 List<string> mibcFiles = new List<string>();
576 foreach (var file in _commandLineOptions.MibcFilePaths)
581 List<ModuleDesc> versionBubbleModules = new List<ModuleDesc>(versionBubbleModulesHash);
583 if (!_commandLineOptions.Composite && inputModules.Count != 1)
585 throw new Exception(string.Format(SR.ErrorMultipleInputFilesCompositeModeOnly, string.Join("; ", inputModules)));
588 ReadyToRunCompilationModuleGroupBase compilationGroup;
589 List<ICompilationRootProvider> compilationRoots = new List<ICompilationRootProvider>();
590 if (singleMethod != null)
592 // Compiling just a single method
593 compilationGroup = new SingleMethodCompilationModuleGroup(
595 _commandLineOptions.Composite,
596 _commandLineOptions.InputBubble,
598 versionBubbleModules,
599 _commandLineOptions.CompileBubbleGenerics,
601 compilationRoots.Add(new SingleMethodRootProvider(singleMethod));
603 else if (_commandLineOptions.CompileNoMethods)
605 compilationGroup = new NoMethodsCompilationModuleGroup(
607 _commandLineOptions.Composite,
608 _commandLineOptions.InputBubble,
610 versionBubbleModules,
611 _commandLineOptions.CompileBubbleGenerics);
615 // Single assembly compilation.
616 compilationGroup = new ReadyToRunSingleAssemblyCompilationModuleGroup(
618 _commandLineOptions.Composite,
619 _commandLineOptions.InputBubble,
621 versionBubbleModules,
622 _commandLineOptions.CompileBubbleGenerics);
625 // Load any profiles generated by method call chain analyis
626 CallChainProfile jsonProfile = null;
628 if (!string.IsNullOrEmpty(_commandLineOptions.CallChainProfileFile))
630 jsonProfile = new CallChainProfile(_commandLineOptions.CallChainProfileFile, typeSystemContext, _referenceableModules);
633 // Examine profile guided information as appropriate
634 ProfileDataManager profileDataManager =
635 new ProfileDataManager(logger,
636 _referenceableModules,
638 versionBubbleModules,
639 _commandLineOptions.CompileBubbleGenerics ? inputModules[0] : null,
644 _commandLineOptions.EmbedPgoData);
646 if (_commandLineOptions.Partial)
647 compilationGroup.ApplyProfilerGuidedCompilationRestriction(profileDataManager);
649 compilationGroup.ApplyProfilerGuidedCompilationRestriction(null);
651 if ((singleMethod == null) && !_commandLineOptions.CompileNoMethods)
653 // For normal compilations add compilation roots.
654 foreach (var module in rootingModules)
656 compilationRoots.Add(new ReadyToRunRootProvider(
659 profileDrivenPartialNGen: _commandLineOptions.Partial));
661 if (!_commandLineOptions.CompositeOrInputBubble)
667 // In single-file compilation mode, use the assembly's DebuggableAttribute to determine whether to optimize
668 // or produce debuggable code if an explicit optimization level was not specified on the command line
669 OptimizationMode optimizationMode = _optimizationMode;
670 if (optimizationMode == OptimizationMode.None && !_commandLineOptions.OptimizeDisabled && !_commandLineOptions.Composite)
672 System.Diagnostics.Debug.Assert(inputModules.Count == 1);
673 optimizationMode = ((EcmaAssembly)inputModules[0].Assembly).HasOptimizationsDisabled() ? OptimizationMode.None : OptimizationMode.Blended;
676 CompositeImageSettings compositeImageSettings = new CompositeImageSettings();
678 if (_commandLineOptions.CompositeKeyFile != null)
680 ImmutableArray<byte> compositeStrongNameKey = File.ReadAllBytes(_commandLineOptions.CompositeKeyFile).ToImmutableArray();
681 if (!IsValidPublicKey(compositeStrongNameKey))
683 throw new Exception(string.Format(SR.ErrorCompositeKeyFileNotPublicKey));
686 compositeImageSettings.PublicKey = compositeStrongNameKey;
693 ReadyToRunCodegenCompilationBuilder builder = new ReadyToRunCodegenCompilationBuilder(
694 typeSystemContext, compilationGroup, _allInputFilePaths.Values, compositeRootPath);
695 string compilationUnitPrefix = "";
696 builder.UseCompilationUnitPrefix(compilationUnitPrefix);
698 ILProvider ilProvider = new ReadyToRunILProvider();
700 DependencyTrackingLevel trackingLevel = _commandLineOptions.DgmlLogFileName == null ?
701 DependencyTrackingLevel.None : (_commandLineOptions.GenerateFullDgmlLog ? DependencyTrackingLevel.All : DependencyTrackingLevel.First);
704 .UseIbcTuning(_commandLineOptions.Tuning)
705 .UseResilience(_commandLineOptions.Resilient)
706 .UseMapFile(_commandLineOptions.Map)
707 .UseMapCsvFile(_commandLineOptions.MapCsv)
708 .UsePdbFile(_commandLineOptions.Pdb, _commandLineOptions.PdbPath)
709 .UsePerfMapFile(_commandLineOptions.PerfMap, _commandLineOptions.PerfMapPath, _commandLineOptions.PerfMapFormatVersion)
710 .UseProfileFile(jsonProfile != null)
711 .UseParallelism(_commandLineOptions.Parallelism)
712 .UseProfileData(profileDataManager)
713 .FileLayoutAlgorithms(_methodLayout, _fileLayout)
714 .UseCompositeImageSettings(compositeImageSettings)
715 .UseJitPath(_commandLineOptions.JitPath)
716 .UseInstructionSetSupport(instructionSetSupport)
717 .UseCustomPESectionAlignment(_commandLineOptions.CustomPESectionAlignment)
718 .UseVerifyTypeAndFieldLayout(_commandLineOptions.VerifyTypeAndFieldLayout)
719 .GenerateOutputFile(outFile)
720 .UseILProvider(ilProvider)
721 .UseBackendOptions(_commandLineOptions.CodegenOptions)
723 .UseDependencyTracking(trackingLevel)
724 .UseCompilationRoots(compilationRoots)
725 .UseOptimizationMode(optimizationMode);
727 if (_commandLineOptions.PrintReproInstructions)
728 builder.UsePrintReproInstructions(CreateReproArgumentString);
730 compilation = builder.ToCompilation();
733 compilation.Compile(outFile);
735 if (_commandLineOptions.DgmlLogFileName != null)
736 compilation.WriteDependencyLog(_commandLineOptions.DgmlLogFileName);
738 compilation.Dispose();
742 private void CheckManagedCppInputFiles(IEnumerable<string> inputPaths)
744 foreach (string inputFilePath in inputPaths)
746 EcmaModule module = _typeSystemContext.GetModuleFromPath(inputFilePath);
747 if ((module.PEReader.PEHeaders.CorHeader.Flags & (CorFlags.ILLibrary | CorFlags.ILOnly)) == (CorFlags)0)
749 throw new CommandLineException(string.Format(SR.ManagedCppNotSupported, inputFilePath));
754 private TypeDesc FindType(CompilerTypeSystemContext context, string typeName)
756 ModuleDesc systemModule = context.SystemModule;
758 TypeDesc foundType = systemModule.GetTypeByCustomAttributeTypeName(typeName, false, (typeDefName, module, throwIfNotFound) =>
760 return (MetadataType)context.GetCanonType(typeDefName)
761 ?? CustomAttributeTypeNameParser.ResolveCustomAttributeTypeDefinitionName(typeDefName, module, throwIfNotFound);
763 if (foundType == null)
764 throw new CommandLineException(string.Format(SR.TypeNotFound, typeName));
769 private MethodDesc CheckAndParseSingleMethodModeArguments(CompilerTypeSystemContext context)
771 if (_commandLineOptions.SingleMethodName == null && _commandLineOptions.SingleMethodTypeName == null && _commandLineOptions.SingleMethodGenericArg == null)
774 if (_commandLineOptions.SingleMethodName == null || _commandLineOptions.SingleMethodTypeName == null)
775 throw new CommandLineException(SR.TypeAndMethodNameNeeded);
777 TypeDesc owningType = FindType(context, _commandLineOptions.SingleMethodTypeName);
779 // TODO: allow specifying signature to distinguish overloads
780 MethodDesc method = null;
781 bool printMethodList = false;
783 foreach (var searchMethod in owningType.GetMethods())
785 if (searchMethod.Name != _commandLineOptions.SingleMethodName)
789 if (_commandLineOptions.SingleMethodIndex != 0)
791 if (curIndex == _commandLineOptions.SingleMethodIndex)
793 method = searchMethod;
801 method = searchMethod;
805 printMethodList = true;
813 foreach (var searchMethod in owningType.GetMethods())
815 if (searchMethod.Name != _commandLineOptions.SingleMethodName)
819 Console.WriteLine($"{curIndex} - {searchMethod}");
821 throw new CommandLineException(SR.SingleMethodIndexNeeded);
825 throw new CommandLineException(string.Format(SR.MethodNotFoundOnType, _commandLineOptions.SingleMethodName, _commandLineOptions.SingleMethodTypeName));
827 if (method.HasInstantiation != (_commandLineOptions.SingleMethodGenericArg != null) ||
828 (method.HasInstantiation && (method.Instantiation.Length != _commandLineOptions.SingleMethodGenericArg.Count)))
830 throw new CommandLineException(
831 string.Format(SR.GenericArgCountMismatch, method.Instantiation.Length, _commandLineOptions.SingleMethodName, _commandLineOptions.SingleMethodTypeName));
834 if (method.HasInstantiation)
836 List<TypeDesc> genericArguments = new List<TypeDesc>();
837 foreach (var argString in _commandLineOptions.SingleMethodGenericArg)
838 genericArguments.Add(FindType(context, argString));
839 method = method.MakeInstantiatedMethod(genericArguments.ToArray());
845 private static string CreateReproArgumentString(MethodDesc method)
847 StringBuilder sb = new StringBuilder();
849 var formatter = new CustomAttributeTypeNameFormatter((IAssemblyDesc)method.Context.SystemModule);
851 sb.Append($"--singlemethodtypename \"{formatter.FormatName(method.OwningType, true)}\"");
852 sb.Append($" --singlemethodname \"{method.Name}\"");
855 foreach (var searchMethod in method.OwningType.GetMethods())
857 if (searchMethod.Name != method.Name)
861 if (searchMethod == method.GetMethodDefinition())
863 sb.Append($" --singlemethodindex {curIndex}");
868 for (int i = 0; i < method.Instantiation.Length; i++)
869 sb.Append($" --singlemethodgenericarg \"{formatter.FormatName(method.Instantiation[i], true)}\"");
871 return sb.ToString();
874 private static bool DumpReproArguments(CodeGenerationFailedException ex)
876 Console.WriteLine(SR.DumpReproInstructions);
878 MethodDesc failingMethod = ex.Method;
879 Console.WriteLine(CreateReproArgumentString(failingMethod));
883 private enum AlgorithmClass
889 private enum AlgorithmSubId
898 HashReplacOwfHash = 11,
904 private struct AlgorithmId
907 private const int AlgorithmClassOffset = 13;
908 private const int AlgorithmClassMask = 0x7;
909 private const int AlgorithmSubIdOffset = 0;
910 private const int AlgorithmSubIdMask = 0x1ff;
912 private readonly uint _flags;
914 public const int RsaSign = 0x00002400;
915 public const int Sha = 0x00008004;
919 get { return _flags != 0; }
922 public AlgorithmClass Class
924 get { return (AlgorithmClass)((_flags >> AlgorithmClassOffset) & AlgorithmClassMask); }
927 public AlgorithmSubId SubId
929 get { return (AlgorithmSubId)((_flags >> AlgorithmSubIdOffset) & AlgorithmSubIdMask); }
932 public AlgorithmId(uint flags)
938 private static readonly ImmutableArray<byte> s_ecmaKey = ImmutableArray.Create(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0 });
940 private const int SnPublicKeyBlobSize = 13;
943 private const byte PublicKeyBlobId = 0x06;
944 private const byte PrivateKeyBlobId = 0x07;
946 // internal for testing
947 internal const int s_publicKeyHeaderSize = SnPublicKeyBlobSize - 1;
949 // From StrongNameInternal.cpp
950 // Checks to see if a public key is a valid instance of a PublicKeyBlob as
951 // defined in StongName.h
952 internal static bool IsValidPublicKey(ImmutableArray<byte> blob)
954 // The number of public key bytes must be at least large enough for the header and one byte of data.
955 if (blob.IsDefault || blob.Length < s_publicKeyHeaderSize + 1)
960 var blobReader = new BinaryReader(new MemoryStream(blob.ToArray()));
962 // Signature algorithm ID
963 var sigAlgId = blobReader.ReadUInt32();
965 var hashAlgId = blobReader.ReadUInt32();
966 // Size of public key data in bytes, not including the header
967 var publicKeySize = blobReader.ReadUInt32();
968 // publicKeySize bytes of public key data
969 var publicKey = blobReader.ReadByte();
971 // The number of public key bytes must be the same as the size of the header plus the size of the public key data.
972 if (blob.Length != s_publicKeyHeaderSize + publicKeySize)
977 // Check for the ECMA key, which does not obey the invariants checked below.
978 if (System.Linq.Enumerable.SequenceEqual(blob, s_ecmaKey))
983 // The public key must be in the wincrypto PUBLICKEYBLOB format
984 if (publicKey != PublicKeyBlobId)
989 var signatureAlgorithmId = new AlgorithmId(sigAlgId);
990 if (signatureAlgorithmId.IsSet && signatureAlgorithmId.Class != AlgorithmClass.Signature)
995 var hashAlgorithmId = new AlgorithmId(hashAlgId);
996 if (hashAlgorithmId.IsSet && (hashAlgorithmId.Class != AlgorithmClass.Hash || hashAlgorithmId.SubId < AlgorithmSubId.Sha1Hash))
1005 private static int Main(string[] args)
1010 return new Program().Run(args);
1012 catch (CodeGenerationFailedException ex) when (DumpReproArguments(ex))
1014 throw new NotSupportedException(); // Unreachable
1019 return new Program().Run(args);
1023 Console.Error.WriteLine(string.Format(SR.ProgramError, e.Message));
1024 Console.Error.WriteLine(e.ToString());