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;
7 using System.Reflection.Metadata;
8 using System.Reflection.PortableExecutable;
9 using System.Runtime.InteropServices;
12 using Internal.CommandLine;
14 using Internal.TypeSystem;
15 using Internal.TypeSystem.Ecma;
19 internal class Program
21 private const string DefaultSystemModule = "System.Private.CoreLib";
23 private CommandLineOptions _commandLineOptions;
24 public TargetOS _targetOS;
25 public TargetArchitecture _targetArchitecture;
26 private bool _armelAbi = false;
27 public OptimizationMode _optimizationMode;
28 private Dictionary<string, string> _inputFilePaths = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
29 private Dictionary<string, string> _unrootedInputFilePaths = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
30 private Dictionary<string, string> _referenceFilePaths = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
31 private CompilerTypeSystemContext _typeSystemContext;
32 private ReadyToRunMethodLayoutAlgorithm _methodLayout;
33 private ReadyToRunFileLayoutAlgorithm _fileLayout;
39 private void InitializeDefaultOptions()
41 // We could offer this as a command line option, but then we also need to
42 // load a different RyuJIT, so this is a future nice to have...
43 if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
44 _targetOS = TargetOS.Windows;
45 else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
46 _targetOS = TargetOS.Linux;
47 else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
48 _targetOS = TargetOS.OSX;
50 throw new NotImplementedException();
52 switch (RuntimeInformation.ProcessArchitecture)
54 case Architecture.X86:
55 _targetArchitecture = TargetArchitecture.X86;
57 case Architecture.X64:
58 _targetArchitecture = TargetArchitecture.X64;
60 case Architecture.Arm:
61 _targetArchitecture = TargetArchitecture.ARM;
63 case Architecture.Arm64:
64 _targetArchitecture = TargetArchitecture.ARM64;
67 throw new NotImplementedException();
71 private void ProcessCommandLine(string[] args)
73 PerfEventSource.StartStopEvents.CommandLineProcessingStart();
74 _commandLineOptions = new CommandLineOptions(args);
75 PerfEventSource.StartStopEvents.CommandLineProcessingStop();
77 if (_commandLineOptions.Help)
82 if (_commandLineOptions.WaitForDebugger)
84 Console.WriteLine(SR.WaitingForDebuggerAttach);
88 if (_commandLineOptions.CompileBubbleGenerics)
90 if (!_commandLineOptions.CompositeOrInputBubble)
92 Console.WriteLine(SR.WarningIgnoringBubbleGenerics);
93 _commandLineOptions.CompileBubbleGenerics = false;
97 _optimizationMode = OptimizationMode.None;
98 if (_commandLineOptions.OptimizeDisabled)
100 if (_commandLineOptions.Optimize || _commandLineOptions.OptimizeSpace || _commandLineOptions.OptimizeTime)
101 Console.WriteLine(SR.WarningOverridingOptimize);
103 else if (_commandLineOptions.OptimizeSpace)
105 if (_commandLineOptions.OptimizeTime)
106 Console.WriteLine(SR.WarningOverridingOptimizeSpace);
107 _optimizationMode = OptimizationMode.PreferSize;
109 else if (_commandLineOptions.OptimizeTime)
110 _optimizationMode = OptimizationMode.PreferSpeed;
111 else if (_commandLineOptions.Optimize)
112 _optimizationMode = OptimizationMode.Blended;
114 foreach (var input in _commandLineOptions.InputFilePaths)
115 Helpers.AppendExpandedPaths(_inputFilePaths, input, true);
117 foreach (var input in _commandLineOptions.UnrootedInputFilePaths)
118 Helpers.AppendExpandedPaths(_unrootedInputFilePaths, input, true);
120 foreach (var reference in _commandLineOptions.ReferenceFilePaths)
121 Helpers.AppendExpandedPaths(_referenceFilePaths, reference, false);
124 int alignment = _commandLineOptions.CustomPESectionAlignment;
127 // Must be a power of two and >= 4096
128 if (alignment < 4096 || (alignment & (alignment - 1)) != 0)
129 throw new CommandLineException(SR.InvalidCustomPESectionAlignment);
132 if (_commandLineOptions.MethodLayout != null)
134 _methodLayout = _commandLineOptions.MethodLayout.ToLowerInvariant() switch
136 "defaultsort" => ReadyToRunMethodLayoutAlgorithm.DefaultSort,
137 "exclusiveweight" => ReadyToRunMethodLayoutAlgorithm.ExclusiveWeight,
138 "hotcold" => ReadyToRunMethodLayoutAlgorithm.HotCold,
139 "hotwarmcold" => ReadyToRunMethodLayoutAlgorithm.HotWarmCold,
140 "callfrequency" => ReadyToRunMethodLayoutAlgorithm.CallFrequency,
141 _ => throw new CommandLineException(SR.InvalidMethodLayout)
145 if (_commandLineOptions.FileLayout != null)
147 _fileLayout = _commandLineOptions.FileLayout.ToLowerInvariant() switch
149 "defaultsort" => ReadyToRunFileLayoutAlgorithm.DefaultSort,
150 "methodorder" => ReadyToRunFileLayoutAlgorithm.MethodOrder,
151 _ => throw new CommandLineException(SR.InvalidFileLayout)
157 private void ConfigureTarget()
160 // Set target Architecture and OS
162 if (_commandLineOptions.TargetArch != null)
164 if (_commandLineOptions.TargetArch.Equals("x86", StringComparison.OrdinalIgnoreCase))
165 _targetArchitecture = TargetArchitecture.X86;
166 else if (_commandLineOptions.TargetArch.Equals("x64", StringComparison.OrdinalIgnoreCase))
167 _targetArchitecture = TargetArchitecture.X64;
168 else if (_commandLineOptions.TargetArch.Equals("arm", StringComparison.OrdinalIgnoreCase))
169 _targetArchitecture = TargetArchitecture.ARM;
170 else if (_commandLineOptions.TargetArch.Equals("armel", StringComparison.OrdinalIgnoreCase))
172 _targetArchitecture = TargetArchitecture.ARM;
175 else if (_commandLineOptions.TargetArch.Equals("arm64", StringComparison.OrdinalIgnoreCase))
176 _targetArchitecture = TargetArchitecture.ARM64;
178 throw new CommandLineException(SR.TargetArchitectureUnsupported);
180 if (_commandLineOptions.TargetOS != null)
182 if (_commandLineOptions.TargetOS.Equals("windows", StringComparison.OrdinalIgnoreCase))
183 _targetOS = TargetOS.Windows;
184 else if (_commandLineOptions.TargetOS.Equals("linux", StringComparison.OrdinalIgnoreCase))
185 _targetOS = TargetOS.Linux;
186 else if (_commandLineOptions.TargetOS.Equals("osx", StringComparison.OrdinalIgnoreCase))
187 _targetOS = TargetOS.OSX;
189 throw new CommandLineException(SR.TargetOSUnsupported);
193 private InstructionSetSupport ConfigureInstructionSetSupport()
195 InstructionSetSupportBuilder instructionSetSupportBuilder = new InstructionSetSupportBuilder(_targetArchitecture);
197 // Ready to run images are built with certain instruction set baselines
198 if ((_targetArchitecture == TargetArchitecture.X86) || (_targetArchitecture == TargetArchitecture.X64))
200 instructionSetSupportBuilder.AddSupportedInstructionSet("sse");
201 instructionSetSupportBuilder.AddSupportedInstructionSet("sse2");
203 else if (_targetArchitecture == TargetArchitecture.ARM64)
205 instructionSetSupportBuilder.AddSupportedInstructionSet("base");
206 instructionSetSupportBuilder.AddSupportedInstructionSet("neon");
210 if (_commandLineOptions.InstructionSet != null)
212 List<string> instructionSetParams = new List<string>();
214 // At this time, instruction sets may only be specified with --input-bubble, as
215 // we do not yet have a stable ABI for all vector parameter/return types.
216 if (!_commandLineOptions.InputBubble)
217 throw new CommandLineException(SR.InstructionSetWithoutInputBubble);
219 // Normalize instruction set format to include implied +.
220 string[] instructionSetParamsInput = _commandLineOptions.InstructionSet.Split(",");
221 for (int i = 0; i < instructionSetParamsInput.Length; i++)
223 string instructionSet = instructionSetParamsInput[i];
225 if (String.IsNullOrEmpty(instructionSet))
226 throw new CommandLineException(String.Format(SR.InstructionSetMustNotBe, ""));
228 char firstChar = instructionSet[0];
229 if ((firstChar != '+') && (firstChar != '-'))
231 instructionSet = "+" + instructionSet;
233 instructionSetParams.Add(instructionSet);
236 Dictionary<string, bool> instructionSetSpecification = new Dictionary<string, bool>();
237 foreach (string instructionSetSpecifier in instructionSetParams)
239 string instructionSet = instructionSetSpecifier.Substring(1, instructionSetSpecifier.Length - 1);
241 bool enabled = instructionSetSpecifier[0] == '+' ? true : false;
244 if (!instructionSetSupportBuilder.AddSupportedInstructionSet(instructionSet))
245 throw new CommandLineException(String.Format(SR.InstructionSetMustNotBe, instructionSet));
249 if (!instructionSetSupportBuilder.RemoveInstructionSetSupport(instructionSet))
250 throw new CommandLineException(String.Format(SR.InstructionSetMustNotBe, instructionSet));
255 instructionSetSupportBuilder.ComputeInstructionSetFlags(out var supportedInstructionSet, out var unsupportedInstructionSet,
256 (string specifiedInstructionSet, string impliedInstructionSet) =>
257 throw new CommandLineException(String.Format(SR.InstructionSetInvalidImplication, specifiedInstructionSet, impliedInstructionSet)));
259 InstructionSetSupportBuilder optimisticInstructionSetSupportBuilder = new InstructionSetSupportBuilder(_targetArchitecture);
261 // Ready to run images are built with certain instruction sets that are optimistically assumed to be present
262 if ((_targetArchitecture == TargetArchitecture.X86) || (_targetArchitecture == TargetArchitecture.X64))
264 // For ReadyToRun we set these hardware features as enabled always, as most
265 // of hardware in the wild supports them. Note that we do not indicate support for AVX, or any other
266 // instruction set which uses the VEX encodings as the presence of those makes otherwise acceptable
267 // code be unusable on hardware which does not support VEX encodings, as well as emulators that do not
268 // support AVX instructions. As the jit generates logic that depends on these features it will call
269 // notifyInstructionSetUsage, which will result in generation of a fixup to verify the behavior of
272 optimisticInstructionSetSupportBuilder.AddSupportedInstructionSet("sse");
273 optimisticInstructionSetSupportBuilder.AddSupportedInstructionSet("sse2");
274 optimisticInstructionSetSupportBuilder.AddSupportedInstructionSet("sse4.1");
275 optimisticInstructionSetSupportBuilder.AddSupportedInstructionSet("sse4.2");
276 optimisticInstructionSetSupportBuilder.AddSupportedInstructionSet("aes");
277 optimisticInstructionSetSupportBuilder.AddSupportedInstructionSet("pclmul");
278 optimisticInstructionSetSupportBuilder.AddSupportedInstructionSet("popcnt");
279 optimisticInstructionSetSupportBuilder.AddSupportedInstructionSet("lzcnt");
282 optimisticInstructionSetSupportBuilder.ComputeInstructionSetFlags(out var optimisticInstructionSet, out _,
283 (string specifiedInstructionSet, string impliedInstructionSet) => throw new NotSupportedException());
284 optimisticInstructionSet.Remove(unsupportedInstructionSet);
285 optimisticInstructionSet.Add(supportedInstructionSet);
287 return new InstructionSetSupport(supportedInstructionSet,
288 unsupportedInstructionSet,
289 optimisticInstructionSet,
290 InstructionSetSupportBuilder.GetNonSpecifiableInstructionSetsForArch(_targetArchitecture),
291 _targetArchitecture);
294 private int Run(string[] args)
296 using (PerfEventSource.StartStopEvents.CompilationEvents())
298 ICompilation compilation;
299 using (PerfEventSource.StartStopEvents.LoadingEvents())
301 InitializeDefaultOptions();
303 ProcessCommandLine(args);
305 if (_commandLineOptions.Help)
307 Console.WriteLine(_commandLineOptions.HelpText);
311 if (_commandLineOptions.OutputFilePath == null)
312 throw new CommandLineException(SR.MissingOutputFile);
315 InstructionSetSupport instructionSetSupport = ConfigureInstructionSetSupport();
318 // Initialize type system context
321 SharedGenericsMode genericsMode = SharedGenericsMode.CanonicalReferenceTypes;
323 var targetDetails = new TargetDetails(_targetArchitecture, _targetOS, _armelAbi ? TargetAbi.CoreRTArmel : TargetAbi.CoreRT, instructionSetSupport.GetVectorTSimdVector());
325 bool versionBubbleIncludesCoreLib = false;
326 if (_commandLineOptions.InputBubble)
328 versionBubbleIncludesCoreLib = true;
332 foreach (var inputFile in _inputFilePaths)
334 if (String.Compare(inputFile.Key, "System.Private.CoreLib", StringComparison.OrdinalIgnoreCase) == 0)
336 versionBubbleIncludesCoreLib = true;
340 if (!versionBubbleIncludesCoreLib)
342 foreach (var inputFile in _unrootedInputFilePaths)
344 if (String.Compare(inputFile.Key, "System.Private.CoreLib", StringComparison.OrdinalIgnoreCase) == 0)
346 versionBubbleIncludesCoreLib = true;
353 _typeSystemContext = new ReadyToRunCompilerContext(targetDetails, genericsMode, versionBubbleIncludesCoreLib);
355 string compositeRootPath = _commandLineOptions.CompositeRootPath;
358 // TODO: To support our pre-compiled test tree, allow input files that aren't managed assemblies since
359 // some tests contain a mixture of both managed and native binaries.
361 // See: https://github.com/dotnet/corert/issues/2785
363 // When we undo this this hack, replace this foreach with
364 // typeSystemContext.InputFilePaths = _inputFilePaths;
366 Dictionary<string, string> allInputFilePaths = new Dictionary<string, string>();
367 Dictionary<string, string> inputFilePaths = new Dictionary<string, string>();
368 List<ModuleDesc> referenceableModules = new List<ModuleDesc>();
369 foreach (var inputFile in _inputFilePaths)
373 var module = _typeSystemContext.GetModuleFromPath(inputFile.Value);
374 allInputFilePaths.Add(inputFile.Key, inputFile.Value);
375 inputFilePaths.Add(inputFile.Key, inputFile.Value);
376 referenceableModules.Add(module);
377 if (compositeRootPath == null)
379 compositeRootPath = Path.GetDirectoryName(inputFile.Value);
382 catch (TypeSystemException.BadImageFormatException)
384 // Keep calm and carry on.
388 Dictionary<string, string> unrootedInputFilePaths = new Dictionary<string, string>();
389 foreach (var unrootedInputFile in _unrootedInputFilePaths)
393 var module = _typeSystemContext.GetModuleFromPath(unrootedInputFile.Value);
394 if (!allInputFilePaths.ContainsKey(unrootedInputFile.Key))
396 allInputFilePaths.Add(unrootedInputFile.Key, unrootedInputFile.Value);
397 unrootedInputFilePaths.Add(unrootedInputFile.Key, unrootedInputFile.Value);
398 referenceableModules.Add(module);
399 if (compositeRootPath == null)
401 compositeRootPath = Path.GetDirectoryName(unrootedInputFile.Value);
405 catch (TypeSystemException.BadImageFormatException)
407 // Keep calm and carry on.
411 CheckManagedCppInputFiles(allInputFilePaths.Values);
413 _typeSystemContext.InputFilePaths = allInputFilePaths;
414 _typeSystemContext.ReferenceFilePaths = _referenceFilePaths;
416 List<EcmaModule> inputModules = new List<EcmaModule>();
417 List<EcmaModule> rootingModules = new List<EcmaModule>();
418 HashSet<ModuleDesc> versionBubbleModulesHash = new HashSet<ModuleDesc>();
419 Guid? inputModuleMvid = null;
421 foreach (var inputFile in inputFilePaths)
423 EcmaModule module = _typeSystemContext.GetModuleFromPath(inputFile.Value);
424 inputModules.Add(module);
425 rootingModules.Add(module);
426 versionBubbleModulesHash.Add(module);
428 if (!_commandLineOptions.Composite && !inputModuleMvid.HasValue)
430 inputModuleMvid = module.MetadataReader.GetGuid(module.MetadataReader.GetModuleDefinition().Mvid);
433 if (!_commandLineOptions.CompositeOrInputBubble)
439 foreach (var unrootedInputFile in unrootedInputFilePaths)
441 EcmaModule module = _typeSystemContext.GetModuleFromPath(unrootedInputFile.Value);
442 inputModules.Add(module);
443 versionBubbleModulesHash.Add(module);
446 string systemModuleName = _commandLineOptions.SystemModule ?? DefaultSystemModule;
447 _typeSystemContext.SetSystemModule((EcmaModule)_typeSystemContext.GetModuleForSimpleName(systemModuleName));
449 if (_typeSystemContext.InputFilePaths.Count == 0)
451 if (_commandLineOptions.InputFilePaths.Count > 0)
453 Console.WriteLine(SR.InputWasNotLoadable);
456 throw new CommandLineException(SR.NoInputFiles);
460 // Initialize compilation group and compilation roots
463 // Single method mode?
464 MethodDesc singleMethod = CheckAndParseSingleMethodModeArguments(_typeSystemContext);
466 var logger = new Logger(Console.Out, _commandLineOptions.Verbose);
468 List<string> mibcFiles = new List<string>();
469 foreach (var file in _commandLineOptions.MibcFilePaths)
474 foreach (var referenceFile in _referenceFilePaths.Values)
478 EcmaModule module = _typeSystemContext.GetModuleFromPath(referenceFile);
479 if (versionBubbleModulesHash.Contains(module))
481 // Ignore reference assemblies that have also been passed as inputs
484 referenceableModules.Add(module);
485 if (_commandLineOptions.InputBubble)
487 // In large version bubble mode add reference paths to the compilation group
488 versionBubbleModulesHash.Add(module);
491 catch { } // Ignore non-managed pe files
494 List<ModuleDesc> versionBubbleModules = new List<ModuleDesc>(versionBubbleModulesHash);
496 if (!_commandLineOptions.Composite && inputModules.Count != 1)
498 throw new Exception(string.Format(SR.ErrorMultipleInputFilesCompositeModeOnly, string.Join("; ", inputModules)));
501 ReadyToRunCompilationModuleGroupBase compilationGroup;
502 List<ICompilationRootProvider> compilationRoots = new List<ICompilationRootProvider>();
503 if (singleMethod != null)
505 // Compiling just a single method
506 compilationGroup = new SingleMethodCompilationModuleGroup(
508 _commandLineOptions.Composite,
509 _commandLineOptions.InputBubble,
511 versionBubbleModules,
512 _commandLineOptions.CompileBubbleGenerics,
514 compilationRoots.Add(new SingleMethodRootProvider(singleMethod));
516 else if (_commandLineOptions.CompileNoMethods)
518 compilationGroup = new NoMethodsCompilationModuleGroup(
520 _commandLineOptions.Composite,
521 _commandLineOptions.InputBubble,
523 versionBubbleModules,
524 _commandLineOptions.CompileBubbleGenerics);
528 // Single assembly compilation.
529 compilationGroup = new ReadyToRunSingleAssemblyCompilationModuleGroup(
531 _commandLineOptions.Composite,
532 _commandLineOptions.InputBubble,
534 versionBubbleModules,
535 _commandLineOptions.CompileBubbleGenerics);
538 // Load any profiles generated by method call chain analyis
539 CallChainProfile jsonProfile = null;
541 if (!string.IsNullOrEmpty(_commandLineOptions.CallChainProfileFile))
543 jsonProfile = new CallChainProfile(_commandLineOptions.CallChainProfileFile, _typeSystemContext, referenceableModules);
546 // Examine profile guided information as appropriate
547 ProfileDataManager profileDataManager =
548 new ProfileDataManager(logger,
549 referenceableModules,
551 versionBubbleModules,
552 _commandLineOptions.CompileBubbleGenerics ? inputModules[0] : null,
557 _commandLineOptions.EmbedPgoData);
559 if (_commandLineOptions.Partial)
560 compilationGroup.ApplyProfilerGuidedCompilationRestriction(profileDataManager);
562 compilationGroup.ApplyProfilerGuidedCompilationRestriction(null);
564 if ((singleMethod == null) && !_commandLineOptions.CompileNoMethods)
566 // For normal compilations add compilation roots.
567 foreach (var module in rootingModules)
569 compilationRoots.Add(new ReadyToRunRootProvider(
572 profileDrivenPartialNGen: _commandLineOptions.Partial));
574 if (!_commandLineOptions.CompositeOrInputBubble)
580 // In single-file compilation mode, use the assembly's DebuggableAttribute to determine whether to optimize
581 // or produce debuggable code if an explicit optimization level was not specified on the command line
582 if (_optimizationMode == OptimizationMode.None && !_commandLineOptions.OptimizeDisabled && !_commandLineOptions.Composite)
584 System.Diagnostics.Debug.Assert(inputModules.Count == 1);
585 _optimizationMode = ((EcmaAssembly)inputModules[0].Assembly).HasOptimizationsDisabled() ? OptimizationMode.None : OptimizationMode.Blended;
592 ReadyToRunCodegenCompilationBuilder builder = new ReadyToRunCodegenCompilationBuilder(
593 _typeSystemContext, compilationGroup, allInputFilePaths.Values, compositeRootPath);
594 string compilationUnitPrefix = "";
595 builder.UseCompilationUnitPrefix(compilationUnitPrefix);
597 ILProvider ilProvider = new ReadyToRunILProvider();
599 DependencyTrackingLevel trackingLevel = _commandLineOptions.DgmlLogFileName == null ?
600 DependencyTrackingLevel.None : (_commandLineOptions.GenerateFullDgmlLog ? DependencyTrackingLevel.All : DependencyTrackingLevel.First);
603 .UseIbcTuning(_commandLineOptions.Tuning)
604 .UseResilience(_commandLineOptions.Resilient)
605 .UseMapFile(_commandLineOptions.Map)
606 .UseMapCsvFile(_commandLineOptions.MapCsv)
607 .UsePdbFile(_commandLineOptions.Pdb, _commandLineOptions.PdbPath)
608 .UsePerfMapFile(_commandLineOptions.PerfMap, _commandLineOptions.PerfMapPath, inputModuleMvid)
609 .UseProfileFile(jsonProfile != null)
610 .UseParallelism(_commandLineOptions.Parallelism)
611 .UseProfileData(profileDataManager)
612 .FileLayoutAlgorithms(_methodLayout, _fileLayout)
613 .UseJitPath(_commandLineOptions.JitPath)
614 .UseInstructionSetSupport(instructionSetSupport)
615 .UseCustomPESectionAlignment(_commandLineOptions.CustomPESectionAlignment)
616 .UseVerifyTypeAndFieldLayout(_commandLineOptions.VerifyTypeAndFieldLayout)
617 .GenerateOutputFile(_commandLineOptions.OutputFilePath)
618 .UseILProvider(ilProvider)
619 .UseBackendOptions(_commandLineOptions.CodegenOptions)
621 .UseDependencyTracking(trackingLevel)
622 .UseCompilationRoots(compilationRoots)
623 .UseOptimizationMode(_optimizationMode);
625 if (_commandLineOptions.PrintReproInstructions)
626 builder.UsePrintReproInstructions(CreateReproArgumentString);
628 compilation = builder.ToCompilation();
631 compilation.Compile(_commandLineOptions.OutputFilePath);
633 if (_commandLineOptions.DgmlLogFileName != null)
634 compilation.WriteDependencyLog(_commandLineOptions.DgmlLogFileName);
636 compilation.Dispose();
642 private void CheckManagedCppInputFiles(IEnumerable<string> inputPaths)
644 foreach (string inputFilePath in inputPaths)
646 EcmaModule module = _typeSystemContext.GetModuleFromPath(inputFilePath);
647 if ((module.PEReader.PEHeaders.CorHeader.Flags & (CorFlags.ILLibrary | CorFlags.ILOnly)) == (CorFlags)0)
649 throw new CommandLineException(string.Format(SR.ManagedCppNotSupported, inputFilePath));
654 private TypeDesc FindType(CompilerTypeSystemContext context, string typeName)
656 ModuleDesc systemModule = context.SystemModule;
658 TypeDesc foundType = systemModule.GetTypeByCustomAttributeTypeName(typeName, false, (typeDefName, module, throwIfNotFound) =>
660 return (MetadataType)context.GetCanonType(typeDefName)
661 ?? CustomAttributeTypeNameParser.ResolveCustomAttributeTypeDefinitionName(typeDefName, module, throwIfNotFound);
663 if (foundType == null)
664 throw new CommandLineException(string.Format(SR.TypeNotFound, typeName));
669 private MethodDesc CheckAndParseSingleMethodModeArguments(CompilerTypeSystemContext context)
671 if (_commandLineOptions.SingleMethodName == null && _commandLineOptions.SingleMethodTypeName == null && _commandLineOptions.SingleMethodGenericArg == null)
674 if (_commandLineOptions.SingleMethodName == null || _commandLineOptions.SingleMethodTypeName == null)
675 throw new CommandLineException(SR.TypeAndMethodNameNeeded);
677 TypeDesc owningType = FindType(context, _commandLineOptions.SingleMethodTypeName);
679 // TODO: allow specifying signature to distinguish overloads
680 MethodDesc method = null;
681 bool printMethodList = false;
683 foreach (var searchMethod in owningType.GetMethods())
685 if (searchMethod.Name != _commandLineOptions.SingleMethodName)
689 if (_commandLineOptions.SingleMethodIndex != 0)
691 if (curIndex == _commandLineOptions.SingleMethodIndex)
693 method = searchMethod;
701 method = searchMethod;
705 printMethodList = true;
713 foreach (var searchMethod in owningType.GetMethods())
715 if (searchMethod.Name != _commandLineOptions.SingleMethodName)
719 Console.WriteLine($"{curIndex} - {searchMethod}");
721 throw new CommandLineException(SR.SingleMethodIndexNeeded);
725 throw new CommandLineException(string.Format(SR.MethodNotFoundOnType, _commandLineOptions.SingleMethodName, _commandLineOptions.SingleMethodTypeName));
727 if (method.HasInstantiation != (_commandLineOptions.SingleMethodGenericArg != null) ||
728 (method.HasInstantiation && (method.Instantiation.Length != _commandLineOptions.SingleMethodGenericArg.Count)))
730 throw new CommandLineException(
731 string.Format(SR.GenericArgCountMismatch, method.Instantiation.Length, _commandLineOptions.SingleMethodName, _commandLineOptions.SingleMethodTypeName));
734 if (method.HasInstantiation)
736 List<TypeDesc> genericArguments = new List<TypeDesc>();
737 foreach (var argString in _commandLineOptions.SingleMethodGenericArg)
738 genericArguments.Add(FindType(context, argString));
739 method = method.MakeInstantiatedMethod(genericArguments.ToArray());
745 private static string CreateReproArgumentString(MethodDesc method)
747 StringBuilder sb = new StringBuilder();
749 var formatter = new CustomAttributeTypeNameFormatter((IAssemblyDesc)method.Context.SystemModule);
751 sb.Append($"--singlemethodtypename \"{formatter.FormatName(method.OwningType, true)}\"");
752 sb.Append($" --singlemethodname \"{method.Name}\"");
755 foreach (var searchMethod in method.OwningType.GetMethods())
757 if (searchMethod.Name != method.Name)
761 if (searchMethod == method.GetMethodDefinition())
763 sb.Append($" --singlemethodindex {curIndex}");
768 for (int i = 0; i < method.Instantiation.Length; i++)
769 sb.Append($" --singlemethodgenericarg \"{formatter.FormatName(method.Instantiation[i], true)}\"");
771 return sb.ToString();
774 private static bool DumpReproArguments(CodeGenerationFailedException ex)
776 Console.WriteLine(SR.DumpReproInstructions);
778 MethodDesc failingMethod = ex.Method;
779 Console.WriteLine(CreateReproArgumentString(failingMethod));
783 private static int Main(string[] args)
788 return new Program().Run(args);
790 catch (CodeGenerationFailedException ex) when (DumpReproArguments(ex))
792 throw new NotSupportedException(); // Unreachable
797 return new Program().Run(args);
801 Console.Error.WriteLine(string.Format(SR.ProgramError, e.Message));
802 Console.Error.WriteLine(e.ToString());