public IMethodNode ShadowConcreteMethod(MethodDesc method, bool isUnboxingStub = false) { return(_shadowConcreteMethods.GetOrAdd(new MethodKey(method, isUnboxingStub))); }
public GenericDictionaryLookup ComputeGenericLookup(MethodDesc contextMethod, ReadyToRunHelperId lookupKind, object targetOfLookup) { GenericContextSource contextSource; if (contextMethod.RequiresInstMethodDescArg()) { contextSource = GenericContextSource.MethodParameter; } else if (contextMethod.RequiresInstMethodTableArg()) { contextSource = GenericContextSource.TypeParameter; } else { Debug.Assert(contextMethod.AcquiresInstMethodTableFromThis()); contextSource = GenericContextSource.ThisObject; } // // Some helpers represent logical concepts that might not be something that can be looked up in a dictionary // // Downgrade type handle for casting to a normal type handle if possible if (lookupKind == ReadyToRunHelperId.TypeHandleForCasting) { var type = (TypeDesc)targetOfLookup; if (!type.IsRuntimeDeterminedType || (!((RuntimeDeterminedType)type).CanonicalType.IsCanonicalDefinitionType(CanonicalFormKind.Universal) && !((RuntimeDeterminedType)type).CanonicalType.IsNullable)) { if (type.IsNullable) { targetOfLookup = type.Instantiation[0]; } lookupKind = ReadyToRunHelperId.NecessaryTypeHandle; } } // We don't have separate entries for necessary type handles to avoid possible duplication if (lookupKind == ReadyToRunHelperId.NecessaryTypeHandle) { lookupKind = ReadyToRunHelperId.TypeHandle; } // Can we do a fixed lookup? Start by checking if we can get to the dictionary. // Context source having a vtable with fixed slots is a prerequisite. if (contextSource == GenericContextSource.MethodParameter || HasFixedSlotVTable(contextMethod.OwningType)) { DictionaryLayoutNode dictionaryLayout; if (contextSource == GenericContextSource.MethodParameter) { dictionaryLayout = _nodeFactory.GenericDictionaryLayout(contextMethod); } else { dictionaryLayout = _nodeFactory.GenericDictionaryLayout(contextMethod.OwningType); } // If the dictionary layout has fixed slots, we can compute the lookup now. Otherwise defer to helper. if (dictionaryLayout.HasFixedSlots) { int pointerSize = _nodeFactory.Target.PointerSize; GenericLookupResult lookup = ReadyToRunGenericHelperNode.GetLookupSignature(_nodeFactory, lookupKind, targetOfLookup); int dictionarySlot = dictionaryLayout.GetSlotForFixedEntry(lookup); if (dictionarySlot != -1) { int dictionaryOffset = dictionarySlot * pointerSize; if (contextSource == GenericContextSource.MethodParameter) { return(GenericDictionaryLookup.CreateFixedLookup(contextSource, dictionaryOffset)); } else { int vtableSlot = VirtualMethodSlotHelper.GetGenericDictionarySlot(_nodeFactory, contextMethod.OwningType); int vtableOffset = EETypeNode.GetVTableOffset(pointerSize) + vtableSlot * pointerSize; return(GenericDictionaryLookup.CreateFixedLookup(contextSource, vtableOffset, dictionaryOffset)); } } } } // Fixed lookup not possible - use helper. return(GenericDictionaryLookup.CreateHelperLookup(contextSource, lookupKind, targetOfLookup)); }
private int Run(string[] args) { InitializeDefaultOptions(); ArgumentSyntax syntax = ParseCommandLine(args); if (_help) { Help(syntax.GetHelpText()); return(1); } if (_outputFilePath == null) { throw new CommandLineException("Output filename must be specified (/out <file>)"); } // // Set target Architecture and OS // if (_targetArchitectureStr != null) { if (_targetArchitectureStr.Equals("x86", StringComparison.OrdinalIgnoreCase)) { _targetArchitecture = TargetArchitecture.X86; } else if (_targetArchitectureStr.Equals("x64", StringComparison.OrdinalIgnoreCase)) { _targetArchitecture = TargetArchitecture.X64; } else if (_targetArchitectureStr.Equals("arm", StringComparison.OrdinalIgnoreCase)) { _targetArchitecture = TargetArchitecture.ARM; } else if (_targetArchitectureStr.Equals("armel", StringComparison.OrdinalIgnoreCase)) { _targetArchitecture = TargetArchitecture.ARM; } else if (_targetArchitectureStr.Equals("arm64", StringComparison.OrdinalIgnoreCase)) { _targetArchitecture = TargetArchitecture.ARM64; } else if (_targetArchitectureStr.Equals("wasm", StringComparison.OrdinalIgnoreCase)) { _targetArchitecture = TargetArchitecture.Wasm32; _isWasmCodegen = true; } else { throw new CommandLineException("Target architecture is not supported"); } } if (_targetOSStr != null) { if (_targetOSStr.Equals("windows", StringComparison.OrdinalIgnoreCase)) { _targetOS = TargetOS.Windows; } else if (_targetOSStr.Equals("linux", StringComparison.OrdinalIgnoreCase)) { _targetOS = TargetOS.Linux; } else if (_targetOSStr.Equals("osx", StringComparison.OrdinalIgnoreCase)) { _targetOS = TargetOS.OSX; } else { throw new CommandLineException("Target OS is not supported"); } } if (_isWasmCodegen) { _targetArchitecture = TargetArchitecture.Wasm32; } InstructionSetSupportBuilder instructionSetSupportBuilder = new InstructionSetSupportBuilder(_targetArchitecture); // The runtime expects certain baselines that the codegen can assume as well. if ((_targetArchitecture == TargetArchitecture.X86) || (_targetArchitecture == TargetArchitecture.X64)) { instructionSetSupportBuilder.AddSupportedInstructionSet("sse"); instructionSetSupportBuilder.AddSupportedInstructionSet("sse2"); } else if (_targetArchitecture == TargetArchitecture.ARM64) { instructionSetSupportBuilder.AddSupportedInstructionSet("base"); instructionSetSupportBuilder.AddSupportedInstructionSet("neon"); } // TODO: read instruction sets from the command line instructionSetSupportBuilder.ComputeInstructionSetFlags(out var supportedInstructionSet, out var unsupportedInstructionSet, (string specifiedInstructionSet, string impliedInstructionSet) => throw new CommandLineException(String.Format("Unsupported combination of instruction sets: {0}/{1}", specifiedInstructionSet, impliedInstructionSet))); InstructionSetSupportBuilder optimisticInstructionSetSupportBuilder = new InstructionSetSupportBuilder(_targetArchitecture); // Optimistically assume some instruction sets are present. if ((_targetArchitecture == TargetArchitecture.X86) || (_targetArchitecture == TargetArchitecture.X64)) { // We set these hardware features as enabled always, as most // of hardware in the wild supports them. Note that we do not indicate support for AVX, or any other // instruction set which uses the VEX encodings as the presence of those makes otherwise acceptable // code be unusable on hardware which does not support VEX encodings, as well as emulators that do not // support AVX instructions. As the jit generates logic that depends on these features it will call // notifyInstructionSetUsage, which will result in generation of a fixup to verify the behavior of // code. // optimisticInstructionSetSupportBuilder.AddSupportedInstructionSet("ssse3"); optimisticInstructionSetSupportBuilder.AddSupportedInstructionSet("aes"); optimisticInstructionSetSupportBuilder.AddSupportedInstructionSet("pclmul"); optimisticInstructionSetSupportBuilder.AddSupportedInstructionSet("lzcnt"); } optimisticInstructionSetSupportBuilder.ComputeInstructionSetFlags(out var optimisticInstructionSet, out _, (string specifiedInstructionSet, string impliedInstructionSet) => throw new NotSupportedException()); optimisticInstructionSet.Remove(unsupportedInstructionSet); optimisticInstructionSet.Add(supportedInstructionSet); var instructionSetSupport = new InstructionSetSupport(supportedInstructionSet, unsupportedInstructionSet, optimisticInstructionSet, InstructionSetSupportBuilder.GetNonSpecifiableInstructionSetsForArch(_targetArchitecture), _targetArchitecture); bool supportsReflection = !_disableReflection && _systemModuleName == DefaultSystemModule; // // Initialize type system context // SharedGenericsMode genericsMode = SharedGenericsMode.CanonicalReferenceTypes; var simdVectorLength = (_isCppCodegen || _isWasmCodegen) ? SimdVectorLength.None : instructionSetSupport.GetVectorTSimdVector(); var targetAbi = _isCppCodegen ? TargetAbi.CppCodegen : TargetAbi.CoreRT; var targetDetails = new TargetDetails(_targetArchitecture, _targetOS, targetAbi, simdVectorLength); CompilerTypeSystemContext typeSystemContext = new CompilerTypeSystemContext(targetDetails, genericsMode, supportsReflection ? DelegateFeature.All : 0); // // TODO: To support our pre-compiled test tree, allow input files that aren't managed assemblies since // some tests contain a mixture of both managed and native binaries. // // See: https://github.com/dotnet/corert/issues/2785 // // When we undo this this hack, replace this foreach with // typeSystemContext.InputFilePaths = _inputFilePaths; // Dictionary <string, string> inputFilePaths = new Dictionary <string, string>(); foreach (var inputFile in _inputFilePaths) { try { var module = typeSystemContext.GetModuleFromPath(inputFile.Value); inputFilePaths.Add(inputFile.Key, inputFile.Value); } catch (TypeSystemException.BadImageFormatException) { // Keep calm and carry on. } } typeSystemContext.InputFilePaths = inputFilePaths; typeSystemContext.ReferenceFilePaths = _referenceFilePaths; if (!typeSystemContext.InputFilePaths.ContainsKey(_systemModuleName) && !typeSystemContext.ReferenceFilePaths.ContainsKey(_systemModuleName)) { throw new CommandLineException($"System module {_systemModuleName} does not exists. Make sure that you specify --systemmodule"); } typeSystemContext.SetSystemModule(typeSystemContext.GetModuleForSimpleName(_systemModuleName)); if (typeSystemContext.InputFilePaths.Count == 0) { throw new CommandLineException("No input files specified"); } // // Initialize compilation group and compilation roots // // Single method mode? MethodDesc singleMethod = CheckAndParseSingleMethodModeArguments(typeSystemContext); CompilationModuleGroup compilationGroup; List <ICompilationRootProvider> compilationRoots = new List <ICompilationRootProvider>(); if (singleMethod != null) { // Compiling just a single method compilationGroup = new SingleMethodCompilationModuleGroup(singleMethod); compilationRoots.Add(new SingleMethodRootProvider(singleMethod)); } else { // Either single file, or multifile library, or multifile consumption. EcmaModule entrypointModule = null; bool systemModuleIsInputModule = false; foreach (var inputFile in typeSystemContext.InputFilePaths) { EcmaModule module = typeSystemContext.GetModuleFromPath(inputFile.Value); if (module.PEReader.PEHeaders.IsExe) { if (entrypointModule != null) { throw new Exception("Multiple EXE modules"); } entrypointModule = module; } if (module == typeSystemContext.SystemModule) { systemModuleIsInputModule = true; } compilationRoots.Add(new ExportedMethodsRootProvider(module)); } if (entrypointModule != null) { compilationRoots.Add(new MainMethodRootProvider(entrypointModule, CreateInitializerList(typeSystemContext))); compilationRoots.Add(new RuntimeConfigurationRootProvider(_runtimeOptions)); } if (_multiFile) { List <EcmaModule> inputModules = new List <EcmaModule>(); foreach (var inputFile in typeSystemContext.InputFilePaths) { EcmaModule module = typeSystemContext.GetModuleFromPath(inputFile.Value); if (entrypointModule == null) { // This is a multifile production build - we need to root all methods compilationRoots.Add(new LibraryRootProvider(module)); } inputModules.Add(module); } compilationGroup = new MultiFileSharedCompilationModuleGroup(typeSystemContext, inputModules); } else { if (entrypointModule == null && !_nativeLib) { throw new Exception("No entrypoint module"); } if (!systemModuleIsInputModule) { compilationRoots.Add(new ExportedMethodsRootProvider((EcmaModule)typeSystemContext.SystemModule)); } compilationGroup = new SingleFileCompilationModuleGroup(); } if (_nativeLib) { // Set owning module of generated native library startup method to compiler generated module, // to ensure the startup method is included in the object file during multimodule mode build compilationRoots.Add(new NativeLibraryInitializerRootProvider(typeSystemContext.GeneratedAssembly, CreateInitializerList(typeSystemContext))); compilationRoots.Add(new RuntimeConfigurationRootProvider(_runtimeOptions)); } if (_rdXmlFilePaths.Count > 0) { Console.WriteLine("Warning: RD.XML processing will change before release (https://github.com/dotnet/corert/issues/5001)"); } foreach (var rdXmlFilePath in _rdXmlFilePaths) { compilationRoots.Add(new RdXmlRootProvider(typeSystemContext, rdXmlFilePath)); } } // // Compile // CompilationBuilder builder; if (_isWasmCodegen) { builder = new WebAssemblyCodegenCompilationBuilder(typeSystemContext, compilationGroup); } else if (_isCppCodegen) { builder = new CppCodegenCompilationBuilder(typeSystemContext, compilationGroup); } else { builder = new RyuJitCompilationBuilder(typeSystemContext, compilationGroup); } string compilationUnitPrefix = _multiFile ? System.IO.Path.GetFileNameWithoutExtension(_outputFilePath) : ""; builder.UseCompilationUnitPrefix(compilationUnitPrefix); PInvokeILEmitterConfiguration pinvokePolicy; if (!_isCppCodegen && !_isWasmCodegen) { pinvokePolicy = new ConfigurablePInvokePolicy(typeSystemContext.Target); } else { pinvokePolicy = new DirectPInvokePolicy(); } RemovedFeature removedFeatures = 0; foreach (string feature in _removedFeatures) { if (feature == "EventSource") { removedFeatures |= RemovedFeature.Etw; } else if (feature == "FrameworkStrings") { removedFeatures |= RemovedFeature.FrameworkResources; } else if (feature == "Globalization") { removedFeatures |= RemovedFeature.Globalization; } else if (feature == "Comparers") { removedFeatures |= RemovedFeature.Comparers; } else if (feature == "SerializationGuard") { removedFeatures |= RemovedFeature.SerializationGuard; } else if (feature == "XmlNonFileStream") { removedFeatures |= RemovedFeature.XmlDownloadNonFileStream; } } ILProvider ilProvider = new CoreRTILProvider(); if (removedFeatures != 0) { ilProvider = new RemovingILProvider(ilProvider, removedFeatures); } var stackTracePolicy = _emitStackTraceData ? (StackTraceEmissionPolicy) new EcmaMethodStackTraceEmissionPolicy() : new NoStackTraceEmissionPolicy(); MetadataBlockingPolicy mdBlockingPolicy; ManifestResourceBlockingPolicy resBlockingPolicy; UsageBasedMetadataGenerationOptions metadataGenerationOptions = UsageBasedMetadataGenerationOptions.IteropILScanning; if (supportsReflection) { mdBlockingPolicy = _noMetadataBlocking ? (MetadataBlockingPolicy) new NoMetadataBlockingPolicy() : new BlockedInternalsBlockingPolicy(typeSystemContext); resBlockingPolicy = (removedFeatures & RemovedFeature.FrameworkResources) != 0 ? new FrameworkStringResourceBlockingPolicy() : (ManifestResourceBlockingPolicy) new NoManifestResourceBlockingPolicy(); metadataGenerationOptions |= UsageBasedMetadataGenerationOptions.AnonymousTypeHeuristic; if (_completeTypesMetadata) { metadataGenerationOptions |= UsageBasedMetadataGenerationOptions.CompleteTypesOnly; } if (_scanReflection) { metadataGenerationOptions |= UsageBasedMetadataGenerationOptions.ReflectionILScanning; } if (_rootAllApplicationAssemblies) { metadataGenerationOptions |= UsageBasedMetadataGenerationOptions.FullUserAssemblyRooting; } } else { mdBlockingPolicy = new FullyBlockedMetadataBlockingPolicy(); resBlockingPolicy = new FullyBlockedManifestResourceBlockingPolicy(); } DynamicInvokeThunkGenerationPolicy invokeThunkGenerationPolicy = new DefaultDynamicInvokeThunkGenerationPolicy(); MetadataManager metadataManager = new UsageBasedMetadataManager( compilationGroup, typeSystemContext, mdBlockingPolicy, resBlockingPolicy, _metadataLogFileName, stackTracePolicy, invokeThunkGenerationPolicy, ilProvider, metadataGenerationOptions); InteropStateManager interopStateManager = new InteropStateManager(typeSystemContext.GeneratedAssembly); InteropStubManager interopStubManager = new UsageBasedInteropStubManager(interopStateManager, pinvokePolicy); // Unless explicitly opted in at the command line, we enable scanner for retail builds by default. // We don't do this for CppCodegen and Wasm, because those codegens are behind. // We also don't do this for multifile because scanner doesn't simulate inlining (this would be // fixable by using a CompilationGroup for the scanner that has a bigger worldview, but // let's cross that bridge when we get there). bool useScanner = _useScanner || (_optimizationMode != OptimizationMode.None && !_isCppCodegen && !_isWasmCodegen && !_multiFile); useScanner &= !_noScanner; builder.UseILProvider(ilProvider); ILScanResults scanResults = null; if (useScanner) { ILScannerBuilder scannerBuilder = builder.GetILScannerBuilder() .UseCompilationRoots(compilationRoots) .UseMetadataManager(metadataManager) .UseSingleThread(enable: _singleThreaded) .UseInteropStubManager(interopStubManager); if (_scanDgmlLogFileName != null) { scannerBuilder.UseDependencyTracking(_generateFullScanDgmlLog ? DependencyTrackingLevel.All : DependencyTrackingLevel.First); } IILScanner scanner = scannerBuilder.ToILScanner(); scanResults = scanner.Scan(); metadataManager = ((UsageBasedMetadataManager)metadataManager).ToAnalysisBasedMetadataManager(); interopStubManager = scanResults.GetInteropStubManager(interopStateManager, pinvokePolicy); } var logger = new Logger(Console.Out, _isVerbose); DebugInformationProvider debugInfoProvider = _enableDebugInfo ? (_ilDump == null ? new DebugInformationProvider() : new ILAssemblyGeneratingMethodDebugInfoProvider(_ilDump, new EcmaOnlyDebugInformationProvider())) : new NullDebugInformationProvider(); DependencyTrackingLevel trackingLevel = _dgmlLogFileName == null ? DependencyTrackingLevel.None : (_generateFullDgmlLog ? DependencyTrackingLevel.All : DependencyTrackingLevel.First); compilationRoots.Add(metadataManager); compilationRoots.Add(interopStubManager); builder .UseInstructionSetSupport(instructionSetSupport) .UseBackendOptions(_codegenOptions) .UseMethodBodyFolding(enable: _methodBodyFolding) .UseSingleThread(enable: _singleThreaded) .UseMetadataManager(metadataManager) .UseInteropStubManager(interopStubManager) .UseLogger(logger) .UseDependencyTracking(trackingLevel) .UseCompilationRoots(compilationRoots) .UseOptimizationMode(_optimizationMode) .UseDebugInfoProvider(debugInfoProvider); if (scanResults != null) { // If we have a scanner, feed the vtable analysis results to the compilation. // This could be a command line switch if we really wanted to. builder.UseVTableSliceProvider(scanResults.GetVTableLayoutInfo()); // If we have a scanner, feed the generic dictionary results to the compilation. // This could be a command line switch if we really wanted to. builder.UseGenericDictionaryLayoutProvider(scanResults.GetDictionaryLayoutInfo()); // If we feed any outputs of the scanner into the compilation, it's essential // we use scanner's devirtualization manager. It prevents optimizing codegens // from accidentally devirtualizing cases that can never happen at runtime // (e.g. devirtualizing a method on a type that never gets allocated). builder.UseDevirtualizationManager(scanResults.GetDevirtualizationManager()); } ICompilation compilation = builder.ToCompilation(); ObjectDumper dumper = _mapFileName != null ? new ObjectDumper(_mapFileName) : null; CompilationResults compilationResults = compilation.Compile(_outputFilePath, dumper); if (_exportsFile != null) { ExportsFileWriter defFileWriter = new ExportsFileWriter(typeSystemContext, _exportsFile); foreach (var compilationRoot in compilationRoots) { if (compilationRoot is ExportedMethodsRootProvider provider) { defFileWriter.AddExportedMethods(provider.ExportedMethods); } } defFileWriter.EmitExportedMethods(); } if (_dgmlLogFileName != null) { compilationResults.WriteDependencyLog(_dgmlLogFileName); } if (scanResults != null) { if (_scanDgmlLogFileName != null) { scanResults.WriteDependencyLog(_scanDgmlLogFileName); } // If the scanner and compiler don't agree on what to compile, the outputs of the scanner might not actually be usable. // We are going to check this two ways: // 1. The methods and types generated during compilation are a subset of method and types scanned // 2. The methods and types scanned are a subset of methods and types compiled (this has a chance to hold for unoptimized builds only). // Check that methods and types generated during compilation are a subset of method and types scanned bool scanningFail = false; DiffCompilationResults(ref scanningFail, compilationResults.CompiledMethodBodies, scanResults.CompiledMethodBodies, "Methods", "compiled", "scanned", method => !(method.GetTypicalMethodDefinition() is EcmaMethod) || method.Name == "ThrowPlatformNotSupportedException"); DiffCompilationResults(ref scanningFail, compilationResults.ConstructedEETypes, scanResults.ConstructedEETypes, "EETypes", "compiled", "scanned", type => !(type.GetTypeDefinition() is EcmaType)); // If optimizations are enabled, the results will for sure not match in the other direction due to inlining, etc. // But there's at least some value in checking the scanner doesn't expand the universe too much in debug. if (_optimizationMode == OptimizationMode.None) { // Check that methods and types scanned are a subset of methods and types compiled // If we find diffs here, they're not critical, but still might be causing a Size on Disk regression. bool dummy = false; // We additionally skip methods in SIMD module because there's just too many intrisics to handle and IL scanner // doesn't expand them. They would show up as noisy diffs. DiffCompilationResults(ref dummy, scanResults.CompiledMethodBodies, compilationResults.CompiledMethodBodies, "Methods", "scanned", "compiled", method => !(method.GetTypicalMethodDefinition() is EcmaMethod) || method.OwningType.IsIntrinsic); DiffCompilationResults(ref dummy, scanResults.ConstructedEETypes, compilationResults.ConstructedEETypes, "EETypes", "scanned", "compiled", type => !(type.GetTypeDefinition() is EcmaType)); } if (scanningFail) { throw new Exception("Scanning failure"); } } if (debugInfoProvider is IDisposable) { ((IDisposable)debugInfoProvider).Dispose(); } return(0); }
/// <summary> /// Returns true if <paramref name="method"/> is an actual native entrypoint. /// There's a distinction between when a method reports it's a PInvoke in the metadata /// versus how it's treated in the compiler. For many PInvoke methods the compiler will generate /// an IL body. The methods with an IL method body shouldn't be treated as PInvoke within the compiler. /// </summary> public static bool IsRawPInvoke(this MethodDesc method) { return(method.IsPInvoke && (method is Internal.IL.Stubs.PInvokeTargetNativeMethod)); }
public bool IsEffectivelySealed(MethodDesc method) { return(_devirtualizationManager.IsEffectivelySealed(method)); }
public sealed override bool VersionsWithMethodBody(MethodDesc method) { return(_versionsWithMethodCache.GetOrAdd(method, VersionsWithMethodUncached)); }
// Internal predicate so that the switches controlling cross module inlining and compilation are independent private bool CrossModuleInlineableInternal(MethodDesc method) { return(_crossModuleInlineableCache.GetOrAdd(method, CrossModuleInlineableUncached)); }
private Utf8String ComputeMangledMethodName(MethodDesc method) { string prependTypeName = null; if (!_mangleForCplusPlus) { prependTypeName = GetMangledTypeName(method.OwningType); } if (method is EcmaMethod) { var deduplicator = new HashSet <string>(); // Add consistent names for all methods of the type, independent on the order in which // they are compiled lock (this) { foreach (var m in method.OwningType.GetMethods()) { string name = SanitizeName(m.Name); name = DisambiguateName(name, deduplicator); deduplicator.Add(name); if (prependTypeName != null) { name = prependTypeName + "__" + name; } _mangledMethodNames = _mangledMethodNames.Add(m, name); } } return(_mangledMethodNames[method]); } string mangledName; var methodDefinition = method.GetTypicalMethodDefinition(); if (methodDefinition != method) { mangledName = GetMangledMethodName(methodDefinition.GetMethodDefinition()).ToString(); var inst = method.Instantiation; string mangledInstantiation = ""; for (int i = 0; i < inst.Length; i++) { string instArgName = GetMangledTypeName(inst[i]); if (_mangleForCplusPlus) { instArgName = instArgName.Replace("::", "_"); } if (i > 0) { mangledInstantiation += "__"; } mangledInstantiation += instArgName; } mangledName += NestMangledName(mangledInstantiation); } else { // Assume that Name is unique for all other methods mangledName = SanitizeName(method.Name); } if (prependTypeName != null) { mangledName = prependTypeName + "__" + mangledName; } Utf8String utf8MangledName = new Utf8String(mangledName); lock (this) { _mangledMethodNames = _mangledMethodNames.Add(method, utf8MangledName); } return(utf8MangledName); }
protected override IMethodNode CreateUnboxingStubNode(MethodDesc method) { // TODO: this is wrong: this returns an assembly stub node return(new UnboxingStubNode(method)); }
public MethodKey(MethodDesc method, bool isUnboxingStub) { Method = method; IsUnboxingStub = isUnboxingStub; }
public DispatchCellKey(MethodDesc target, string callsiteId) { Target = target; CallsiteId = callsiteId; }
public EmbeddedObjectNode EagerCctorIndirection(MethodDesc cctorMethod) { return(_eagerCctorIndirectionNodes.GetOrAdd(cctorMethod)); }
public DependencyNodeCore <NodeFactory> VirtualMethodUse(MethodDesc decl) { return(_virtMethods.GetOrAdd(decl)); }
public IMethodNode RuntimeDeterminedMethod(MethodDesc method) { return(_runtimeDeterminedMethods.GetOrAdd(method)); }
protected override void ComputeDependencyNodeDependencies(List <DependencyNodeCore <NodeFactory> > obj) { using (PerfEventSource.StartStopEvents.JitEvents()) { Action <DependencyNodeCore <NodeFactory> > compileOneMethod = (DependencyNodeCore <NodeFactory> dependency) => { MethodWithGCInfo methodCodeNodeNeedingCode = dependency as MethodWithGCInfo; MethodDesc method = methodCodeNodeNeedingCode.Method; if (Logger.IsVerbose) { string methodName = method.ToString(); Logger.Writer.WriteLine("Compiling " + methodName); } try { using (PerfEventSource.StartStopEvents.JitMethodEvents()) { // Create only 1 CorInfoImpl per thread. // This allows SuperPMI to rely on non-reuse of handles in ObjectToHandle CorInfoImpl corInfoImpl = _corInfoImpls.GetValue(Thread.CurrentThread, thread => new CorInfoImpl(this)); corInfoImpl.CompileMethod(methodCodeNodeNeedingCode); } } catch (TypeSystemException ex) { // If compilation fails, don't emit code for this method. It will be Jitted at runtime if (Logger.IsVerbose) { Logger.Writer.WriteLine($"Warning: Method `{method}` was not compiled because: {ex.Message}"); } } catch (RequiresRuntimeJitException ex) { if (Logger.IsVerbose) { Logger.Writer.WriteLine($"Info: Method `{method}` was not compiled because `{ex.Message}` requires runtime JIT"); } } catch (CodeGenerationFailedException ex) when(_resilient) { if (Logger.IsVerbose) { Logger.Writer.WriteLine($"Warning: Method `{method}` was not compiled because `{ex.Message}` requires runtime JIT"); } } }; // Use only main thread to compile if parallelism is 1. This allows SuperPMI to rely on non-reuse of handles in ObjectToHandle if (_parallelism == 1) { foreach (var dependency in obj) { compileOneMethod(dependency); } } else { ParallelOptions options = new ParallelOptions { MaxDegreeOfParallelism = _parallelism }; Parallel.ForEach(obj, options, compileOneMethod); } } if (_methodILCache.Count > 1000) { _methodILCache = new ILCache(_methodILCache.ILProvider, NodeFactory.CompilationModuleGroup); } }
public static IEnumerable <MethodDesc> CollectSupportedMethods(GameObject gameObject) { if (gameObject == null) { return(Enumerable.Empty <MethodDesc>()); } var supportedMethods = new List <MethodDesc>(); var behaviours = gameObject.GetComponents <MonoBehaviour>(); foreach (var behaviour in behaviours) { if (behaviour == null) { continue; } var type = behaviour.GetType(); while (type != typeof(MonoBehaviour) && type != null) { var methods = type.GetMethods( BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.DeclaredOnly); foreach (var method in methods) { var name = method.Name; if (!IsSupportedMethodName(name)) { continue; } var parameters = method.GetParameters(); if (parameters.Length > 1) //methods with multiple parameters are not supported { continue; } var parameterType = ParameterType.None; if (parameters.Length == 1) { var paramType = parameters[0].ParameterType; if (paramType == typeof(string)) { parameterType = ParameterType.String; } else if (paramType == typeof(float)) { parameterType = ParameterType.Float; } else if (paramType == typeof(int)) { parameterType = ParameterType.Int; } else if (paramType == typeof(Object) || paramType.IsSubclassOf(typeof(Object))) { parameterType = ParameterType.Object; } else { continue; } } var supportedMethod = new MethodDesc { name = name, type = parameterType }; // Since AnimationEvents only stores method name, it can't handle functions with multiple overloads. // Only retrieve first found function, but discard overloads. var existingMethodIndex = supportedMethods.FindIndex(m => m.name == name); if (existingMethodIndex != -1) { // The method is only ambiguous if it has a different signature to the one we saw before var existingMethod = supportedMethods[existingMethodIndex]; existingMethod.isOverload = existingMethod.type != parameterType; } else { supportedMethods.Add(supportedMethod); } } type = type.BaseType; } } return(supportedMethods); }
public ModuleToken GetModuleTokenForMethod(MethodDesc method, bool throwIfNotFound = true) { return(Resolver.GetModuleTokenForMethod(method, throwIfNotFound)); }
private void ImportCall(ILOpcode opcode, int token) { // Strip runtime determined characteristics off of the method (because that's how RyuJIT operates) var runtimeDeterminedMethod = (MethodDesc)_methodIL.GetObject(token); MethodDesc method = runtimeDeterminedMethod; if (runtimeDeterminedMethod.IsRuntimeDeterminedExactMethod) { method = runtimeDeterminedMethod.GetCanonMethodTarget(CanonicalFormKind.Specific); } if (method.IsRawPInvoke()) { // Raw P/invokes don't have any dependencies. return; } string reason = null; switch (opcode) { case ILOpcode.newobj: reason = "newobj"; break; case ILOpcode.call: reason = "call"; break; case ILOpcode.callvirt: reason = "callvirt"; break; case ILOpcode.ldftn: reason = "ldftn"; break; case ILOpcode.ldvirtftn: reason = "ldvirtftn"; break; default: Debug.Assert(false); break; } // If we're scanning the fallback body because scanning the real body failed, don't trigger cctor. // Accessing the cctor could have been a reason why we failed. if (!_isFallbackBodyCompilation) { // Do we need to run the cctor? TypeDesc owningType = runtimeDeterminedMethod.OwningType; if (_factory.TypeSystemContext.HasLazyStaticConstructor(owningType)) { // For beforefieldinit, we can wait for field access. if (!((MetadataType)owningType).IsBeforeFieldInit) { // Accessing the static base will trigger the cctor. if (owningType.IsRuntimeDeterminedSubtype) { _dependencies.Add(GetGenericLookupHelper(ReadyToRunHelperId.GetNonGCStaticBase, owningType), reason); } else { _dependencies.Add(_factory.ReadyToRunHelper(ReadyToRunHelperId.GetNonGCStaticBase, owningType), reason); } } } } if (opcode == ILOpcode.newobj) { TypeDesc owningType = runtimeDeterminedMethod.OwningType; if (owningType.IsString) { // String .ctor handled specially below } else { // Nullable needs to be unwrapped. if (owningType.IsNullable) { owningType = owningType.Instantiation[0]; } if (owningType.IsRuntimeDeterminedSubtype) { _dependencies.Add(GetGenericLookupHelper(ReadyToRunHelperId.TypeHandle, owningType), reason); } else { _dependencies.Add(_factory.ConstructedTypeSymbol(owningType), reason); } if (owningType.IsMdArray) { _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.NewMultiDimArr_NonVarArg), reason); return; } else { _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.NewObject), reason); } } if (owningType.IsDelegate) { // If this is a verifiable delegate construction sequence, the previous instruction is a ldftn/ldvirtftn if (_previousInstructionOffset >= 0 && _ilBytes[_previousInstructionOffset] == (byte)ILOpcode.prefix1) { // TODO: for ldvirtftn we need to also check for the `dup` instruction, otherwise this is a normal newobj. ILOpcode previousOpcode = (ILOpcode)(0x100 + _ilBytes[_previousInstructionOffset + 1]); if (previousOpcode == ILOpcode.ldvirtftn || previousOpcode == ILOpcode.ldftn) { int delTargetToken = ReadILTokenAt(_previousInstructionOffset + 2); var delTargetMethod = (MethodDesc)_methodIL.GetObject(delTargetToken); TypeDesc canonDelegateType = method.OwningType.ConvertToCanonForm(CanonicalFormKind.Specific); DelegateCreationInfo info = _compilation.GetDelegateCtor(canonDelegateType, delTargetMethod, previousOpcode == ILOpcode.ldvirtftn); if (info.NeedsRuntimeLookup) { _dependencies.Add(GetGenericLookupHelper(ReadyToRunHelperId.DelegateCtor, info), reason); } else { _dependencies.Add(_factory.ReadyToRunHelper(ReadyToRunHelperId.DelegateCtor, info), reason); } return; } } } } if (method.OwningType.IsDelegate && method.Name == "Invoke") { // TODO: might not want to do this if scanning for reflection. // This is expanded as an intrinsic, not a function call. return; } if (method.IsIntrinsic) { if (IsRuntimeHelpersInitializeArray(method)) { if (_previousInstructionOffset >= 0 && _ilBytes[_previousInstructionOffset] == (byte)ILOpcode.ldtoken) { return; } } if (IsRuntimeTypeHandleGetValueInternal(method)) { if (_previousInstructionOffset >= 0 && _ilBytes[_previousInstructionOffset] == (byte)ILOpcode.ldtoken) { return; } } } TypeDesc exactType = method.OwningType; bool resolvedConstraint = false; bool forceUseRuntimeLookup = false; MethodDesc methodAfterConstraintResolution = method; if (_constrained != null) { // We have a "constrained." call. Try a partial resolve of the constraint call. Note that this // will not necessarily resolve the call exactly, since we might be compiling // shared generic code - it may just resolve it to a candidate suitable for // JIT compilation, and require a runtime lookup for the actual code pointer // to call. MethodDesc directMethod = _constrained.GetClosestDefType().TryResolveConstraintMethodApprox(method.OwningType, method, out forceUseRuntimeLookup); if (directMethod == null && _constrained.IsEnum) { // Constrained calls to methods on enum methods resolve to System.Enum's methods. System.Enum is a reference // type though, so we would fail to resolve and box. We have a special path for those to avoid boxing. directMethod = _compilation.TypeSystemContext.TryResolveConstrainedEnumMethod(_constrained, method); } if (directMethod != null) { // Either // 1. no constraint resolution at compile time (!directMethod) // OR 2. no code sharing lookup in call // OR 3. we have have resolved to an instantiating stub methodAfterConstraintResolution = directMethod; Debug.Assert(!methodAfterConstraintResolution.OwningType.IsInterface); resolvedConstraint = true; exactType = _constrained; } else if (_constrained.IsValueType) { // We'll need to box `this`. AddBoxingDependencies(_constrained, reason); } _constrained = null; } MethodDesc targetMethod = methodAfterConstraintResolution; bool exactContextNeedsRuntimeLookup; if (targetMethod.HasInstantiation) { exactContextNeedsRuntimeLookup = targetMethod.IsSharedByGenericInstantiations; } else { exactContextNeedsRuntimeLookup = exactType.IsCanonicalSubtype(CanonicalFormKind.Any); } // // Determine whether to perform direct call // bool directCall = false; if (targetMethod.Signature.IsStatic) { // Static methods are always direct calls directCall = true; } else if (targetMethod.OwningType.IsInterface) { // Force all interface calls to be interpreted as if they are virtual. directCall = false; } else if ((opcode != ILOpcode.callvirt && opcode != ILOpcode.ldvirtftn) || resolvedConstraint) { directCall = true; } else { if (!targetMethod.IsVirtual || targetMethod.IsFinal || targetMethod.OwningType.IsSealed()) { directCall = true; } } bool allowInstParam = opcode != ILOpcode.ldvirtftn && opcode != ILOpcode.ldftn; if (directCall && !allowInstParam && targetMethod.GetCanonMethodTarget(CanonicalFormKind.Specific).RequiresInstArg()) { // Needs a single address to call this method but the method needs a hidden argument. // We need a fat function pointer for this that captures both things. if (exactContextNeedsRuntimeLookup) { _dependencies.Add(GetGenericLookupHelper(ReadyToRunHelperId.MethodEntry, runtimeDeterminedMethod), reason); } else { _dependencies.Add(_factory.FatFunctionPointer(runtimeDeterminedMethod), reason); } } else if (directCall) { bool referencingArrayAddressMethod = false; if (targetMethod.IsIntrinsic) { // If this is an intrinsic method with a callsite-specific expansion, this will replace // the method with a method the intrinsic expands into. If it's not the special intrinsic, // method stays unchanged. targetMethod = _compilation.ExpandIntrinsicForCallsite(targetMethod, _canonMethod); // Array address method requires special dependency tracking. referencingArrayAddressMethod = targetMethod.IsArrayAddressMethod(); } MethodDesc concreteMethod = targetMethod; targetMethod = targetMethod.GetCanonMethodTarget(CanonicalFormKind.Specific); if (targetMethod.IsConstructor && targetMethod.OwningType.IsString) { _dependencies.Add(_factory.StringAllocator(targetMethod), reason); } else if (exactContextNeedsRuntimeLookup) { if (targetMethod.IsSharedByGenericInstantiations && !resolvedConstraint && !referencingArrayAddressMethod) { _dependencies.Add(_factory.RuntimeDeterminedMethod(runtimeDeterminedMethod), reason); } else { Debug.Assert(!forceUseRuntimeLookup); _dependencies.Add(_factory.MethodEntrypoint(targetMethod), reason); } } else { ISymbolNode instParam = null; if (targetMethod.RequiresInstMethodDescArg()) { instParam = _compilation.NodeFactory.MethodGenericDictionary(concreteMethod); } else if (targetMethod.RequiresInstMethodTableArg() || referencingArrayAddressMethod) { // Ask for a constructed type symbol because we need the vtable to get to the dictionary instParam = _compilation.NodeFactory.ConstructedTypeSymbol(concreteMethod.OwningType); } if (instParam != null) { _dependencies.Add(instParam, reason); if (!referencingArrayAddressMethod) { _dependencies.Add(_compilation.NodeFactory.ShadowConcreteMethod(concreteMethod), reason); } else { // We don't want array Address method to be modeled in the generic dependency analysis. // The method doesn't actually have runtime determined dependencies (won't do // any generic lookups). _dependencies.Add(_compilation.NodeFactory.MethodEntrypoint(targetMethod), reason); } } else if (targetMethod.AcquiresInstMethodTableFromThis()) { _dependencies.Add(_compilation.NodeFactory.ShadowConcreteMethod(concreteMethod), reason); } else { _dependencies.Add(_compilation.NodeFactory.MethodEntrypoint(targetMethod), reason); } } } else if (method.HasInstantiation) { // Generic virtual method call if (exactContextNeedsRuntimeLookup) { _dependencies.Add(GetGenericLookupHelper(ReadyToRunHelperId.MethodHandle, runtimeDeterminedMethod), reason); } else { _dependencies.Add(_factory.RuntimeMethodHandle(runtimeDeterminedMethod), reason); } _dependencies.Add(GetHelperEntrypoint(ReadyToRunHelper.GVMLookupForSlot), reason); } else { ReadyToRunHelperId helper; if (opcode == ILOpcode.ldvirtftn) { helper = ReadyToRunHelperId.ResolveVirtualFunction; } else { Debug.Assert(opcode == ILOpcode.callvirt); helper = ReadyToRunHelperId.VirtualCall; } if (exactContextNeedsRuntimeLookup && targetMethod.OwningType.IsInterface) { _dependencies.Add(GetGenericLookupHelper(helper, runtimeDeterminedMethod), reason); } else { // Get the slot defining method to make sure our virtual method use tracking gets this right. // For normal C# code the targetMethod will always be newslot. MethodDesc slotDefiningMethod = targetMethod.IsNewSlot ? targetMethod : MetadataVirtualMethodAlgorithm.FindSlotDefiningMethodForVirtualMethod(targetMethod); _dependencies.Add(_factory.ReadyToRunHelper(helper, slotDefiningMethod), reason); } } }
private bool CrossModuleCompileableUncached(MethodDesc method) { if (!CrossModuleInlineableInternal(method)) { return(false); } // Only allow generics, non-generics should be compiled into the defining module if (!(method.HasInstantiation || method.OwningType.HasInstantiation)) { return(false); } if (CompileAllPossibleCrossModuleCode) { return(true); } EcmaModule methodDefiningModule = ((MetadataType)method.OwningType.GetTypeDefinition()).Module as EcmaModule; if (_compilationModuleSet.Contains(methodDefiningModule)) { return(true); } // Alternate algorithm for generic method placement // This is designed to provide a second location to look for a generic instantiation that isn't the // defining module of the method. This algorithm is designed to be: // 1. Cheap to compute // 2. Able to find many generic instantiations assuming a fairly low level of generic complexity // 3. Particularly useful for cases where a second module instantiates a generic from a defining module // over types entirely defined in a second module. // 4. Simple to implement in a compatible fashion in crossgen2 and runtime, so that the runtime and compile can agree // on code that should be useable. See ReadyToRunInfo::ComputeAlternateGenericLocationForR2RCode // for the native implementation. EcmaModule alternateGenericLocationModule = ComputeAlternateGenericLocationForR2RCodeFromInstantiation(methodDefiningModule, method.Instantiation); if (alternateGenericLocationModule == null) { alternateGenericLocationModule = ComputeAlternateGenericLocationForR2RCodeFromInstantiation(methodDefiningModule, method.OwningType.Instantiation); } if (alternateGenericLocationModule != null) { return(_compilationModuleSet.Contains(alternateGenericLocationModule)); } return(false); EcmaModule ComputeAlternateGenericLocationForR2RCodeFromInstantiation(ModuleDesc definitionModule, Instantiation inst) { foreach (var instArgFixed in inst) { var instArg = instArgFixed; while (instArg.IsParameterizedType) { instArg = instArg.GetParameterType(); } // System.__Canon does not contribute to logical loader module if (instArg.IsCanonicalDefinitionType(CanonicalFormKind.Any)) { continue; } if (instArg.IsPrimitive) { continue; } if (instArg.GetTypeDefinition() is MetadataType metadataType) { if (metadataType.Module != definitionModule) { return(metadataType.Module as EcmaModule); } } } return(null); } }
public void GetCallRefMap(MethodDesc method) { TransitionBlock transitionBlock = TransitionBlock.FromTarget(method.Context.Target); bool hasThis = (method.Signature.Flags & MethodSignatureFlags.Static) == 0; bool isVarArg = false; TypeHandle returnType = new TypeHandle(method.Signature.ReturnType); TypeHandle[] parameterTypes = new TypeHandle[method.Signature.Length]; for (int parameterIndex = 0; parameterIndex < parameterTypes.Length; parameterIndex++) { parameterTypes[parameterIndex] = new TypeHandle(method.Signature[parameterIndex]); } CallingConventions callingConventions = (hasThis ? CallingConventions.ManagedInstance : CallingConventions.ManagedStatic); bool hasParamType = method.GetCanonMethodTarget(CanonicalFormKind.Specific).RequiresInstArg(); bool extraFunctionPointerArg = false; bool[] forcedByRefParams = new bool[parameterTypes.Length]; bool skipFirstArg = false; bool extraObjectFirstArg = false; ArgIteratorData argIteratorData = new ArgIteratorData(hasThis, isVarArg, parameterTypes, returnType); ArgIterator argit = new ArgIterator( method.Context, argIteratorData, callingConventions, hasParamType, extraFunctionPointerArg, forcedByRefParams, skipFirstArg, extraObjectFirstArg); int nStackBytes = argit.SizeOfFrameArgumentArray(); // Allocate a fake stack CORCOMPILE_GCREFMAP_TOKENS[] fakeStack = new CORCOMPILE_GCREFMAP_TOKENS[transitionBlock.SizeOfTransitionBlock + nStackBytes]; // Fill it in FakeGcScanRoots(method, argit, fakeStack); // Encode the ref map uint nStackSlots; if (_target.Architecture == TargetArchitecture.X86) { uint cbStackPop = argit.CbStackPop(); WriteStackPop(cbStackPop / (uint)_target.PointerSize); nStackSlots = (uint)(nStackBytes / _target.PointerSize + _transitionBlock.NumArgumentRegisters); } else { nStackSlots = (uint)((transitionBlock.SizeOfTransitionBlock + nStackBytes - _transitionBlock.OffsetOfFirstGCRefMapSlot) / _target.PointerSize); } for (uint pos = 0; pos < nStackSlots; pos++) { int ofs; if (_target.Architecture == TargetArchitecture.X86) { ofs = (int)(pos < _transitionBlock.NumArgumentRegisters ? _transitionBlock.OffsetOfArgumentRegisters + _transitionBlock.SizeOfArgumentRegisters - (pos + 1) * _target.PointerSize : _transitionBlock.OffsetOfArgs + (pos - _transitionBlock.NumArgumentRegisters) * _target.PointerSize); } else { ofs = (int)(_transitionBlock.OffsetOfFirstGCRefMapSlot + pos * _target.PointerSize); } CORCOMPILE_GCREFMAP_TOKENS token = fakeStack[ofs]; if (token != CORCOMPILE_GCREFMAP_TOKENS.GCREFMAP_SKIP) { WriteToken(pos, (byte)token); } } Flush(); }
public sealed override bool GeneratesPInvoke(MethodDesc method) { return(!Marshaller.IsMarshallingRequired(method)); }
private bool ResolveGenericVirtualMethodTarget(RuntimeTypeHandle targetTypeHandle, RuntimeTypeHandle declaringTypeHandle, RuntimeTypeHandle[] genericArguments, MethodNameAndSignature callingMethodNameAndSignature, out IntPtr methodPointer, out IntPtr dictionaryPointer) { if (IsPregeneratedOrTemplateRuntimeTypeHandle(targetTypeHandle)) { // If the target type isn't dynamic, or at least is template type generated, the static lookup logic is what we want. return(ResolveGenericVirtualMethodTarget_Static(targetTypeHandle, declaringTypeHandle, genericArguments, callingMethodNameAndSignature, out methodPointer, out dictionaryPointer)); } else { #if SUPPORTS_NATIVE_METADATA_TYPE_LOADING methodPointer = IntPtr.Zero; dictionaryPointer = IntPtr.Zero; TypeSystemContext context = TypeSystemContextFactory.Create(); DefType targetType = (DefType)context.ResolveRuntimeTypeHandle(targetTypeHandle); // Method being called... MethodDesc targetVirtualMethod = ResolveTypeHandleAndMethodNameAndSigToVirtualMethodDesc(context, declaringTypeHandle, callingMethodNameAndSignature); if (targetVirtualMethod == null) { // If we can't find the method in the type system, it must only be present in the static environment. Search there instead. TypeSystemContextFactory.Recycle(context); return(ResolveGenericVirtualMethodTarget_Static(targetTypeHandle, declaringTypeHandle, genericArguments, callingMethodNameAndSignature, out methodPointer, out dictionaryPointer)); } MethodDesc dispatchMethod = targetType.FindVirtualFunctionTargetMethodOnObjectType(targetVirtualMethod); if (dispatchMethod == null) { return(false); } Instantiation targetMethodInstantiation = context.ResolveRuntimeTypeHandles(genericArguments); MethodDesc instantiatedDispatchMethod = dispatchMethod.Context.ResolveGenericMethodInstantiation(dispatchMethod.OwningType.IsValueType /* get the unboxing stub */, dispatchMethod.OwningType.GetClosestDefType(), dispatchMethod.NameAndSignature, targetMethodInstantiation, IntPtr.Zero, false); GenericDictionaryCell cell = GenericDictionaryCell.CreateMethodCell(instantiatedDispatchMethod, false); using (LockHolder.Hold(_typeLoaderLock)) { // Now that we hold the lock, we may find that existing types can now find // their associated RuntimeTypeHandle. Flush the type builder states as a way // to force the reresolution of RuntimeTypeHandles which couldn't be found before. context.FlushTypeBuilderStates(); TypeBuilder.ResolveSingleCell(cell, out methodPointer); } TypeSystemContextFactory.Recycle(context); return(true); #else methodPointer = IntPtr.Zero; dictionaryPointer = IntPtr.Zero; Environment.FailFast("GVM Resolution for non template or pregenerated type"); return(false); #endif } }
/// <summary> /// Return true when the method is marked as non-versionable. Non-versionable methods /// may be freely inlined into ReadyToRun images even when they don't reside in the /// same version bubble as the module being compiled. /// </summary> /// <param name="method">Method to check</param> /// <returns>True when the method is marked as non-versionable, false otherwise.</returns> public static bool IsNonVersionable(this MethodDesc method) { return(method.HasCustomAttribute("System.Runtime.Versioning", "NonVersionableAttribute")); }
/// <summary> /// Generates a specialized method body for EqualityComparer`1.Create or returns null if no specialized body can be generated. /// </summary> public static MethodIL EmitEqualityComparerCreate(MethodDesc target) { return(EmitComparerAndEqualityComparerCreateCommon(target, "EqualityComparer", "IEquatable`1")); }
public MethodDesc ResolveVirtualMethod(MethodDesc declMethod, TypeDesc implType) { return(_devirtualizationManager.ResolveVirtualMethod(declMethod, implType)); }
public override ObjectData GetData(NodeFactory factory, bool relocsOnly = false) { // This node does not trigger generation of other nodes. if (relocsOnly) { return(new ObjectData(Array.Empty <byte>(), Array.Empty <Relocation>(), 1, new ISymbolDefinitionNode[] { this })); } Dictionary <EcmaMethod, HashSet <EcmaMethod> > inlineeToInliners = new Dictionary <EcmaMethod, HashSet <EcmaMethod> >(); // Build a map from inlinee to the list of inliners // We are only interested in the generic definitions of these. foreach (MethodWithGCInfo methodNode in factory.EnumerateCompiledMethods()) { MethodDesc[] inlinees = methodNode.InlinedMethods; MethodDesc inliner = methodNode.Method; EcmaMethod inlinerDefinition = (EcmaMethod)inliner.GetTypicalMethodDefinition(); if (inlinerDefinition.Module != _module) { // Only encode inlining info for inliners within the active module continue; } foreach (MethodDesc inlinee in inlinees) { MethodDesc inlineeDefinition = inlinee.GetTypicalMethodDefinition(); if (!(inlineeDefinition is EcmaMethod ecmaInlineeDefinition)) { // We don't record non-ECMA methods because they don't have tokens that // diagnostic tools could reason about anyway. continue; } if (!inlineeToInliners.TryGetValue(ecmaInlineeDefinition, out HashSet <EcmaMethod> inliners)) { inliners = new HashSet <EcmaMethod>(); inlineeToInliners.Add(ecmaInlineeDefinition, inliners); } inliners.Add((EcmaMethod)inlinerDefinition); } } // Serialize the map as a hash table NativeWriter writer = new NativeWriter(); Section section = writer.NewSection(); VertexHashtable hashtable = new VertexHashtable(); section.Place(hashtable); foreach (var inlineeWithInliners in inlineeToInliners) { EcmaMethod inlinee = inlineeWithInliners.Key; int inlineeRid = MetadataTokens.GetRowNumber(inlinee.Handle); int hashCode = ReadyToRunHashCode.ModuleNameHashCode(inlinee.Module); hashCode ^= inlineeRid; // Format of the sequence: // Inlinee RID with flag in the lowest bit // - if flag is set, followed by module ID // Followed by inliner RIDs deltas with flag in the lowest bit // - if flag is set, followed by module ID var sig = new VertexSequence(); bool isForeignInlinee = inlinee.Module != _module; sig.Append(new UnsignedConstant((uint)(inlineeRid << 1 | (isForeignInlinee ? 1 : 0)))); if (isForeignInlinee) { sig.Append(new UnsignedConstant((uint)factory.ManifestMetadataTable.ModuleToIndex(inlinee.Module))); } List <EcmaMethod> sortedInliners = new List <EcmaMethod>(inlineeWithInliners.Value); sortedInliners.Sort((a, b) => { if (a == b) { return(0); } int aRid = MetadataTokens.GetRowNumber(a.Handle); int bRid = MetadataTokens.GetRowNumber(b.Handle); if (aRid < bRid) { return(-1); } else if (aRid > bRid) { return(1); } int result = a.Module.CompareTo(b.Module); Debug.Assert(result != 0); return(result); }); int baseRid = 0; foreach (EcmaMethod inliner in sortedInliners) { int inlinerRid = MetadataTokens.GetRowNumber(inliner.Handle); int ridDelta = inlinerRid - baseRid; baseRid = inlinerRid; Debug.Assert(ridDelta >= 0); bool isForeignInliner = inliner.Module != _module; sig.Append(new UnsignedConstant((uint)(ridDelta << 1 | (isForeignInliner ? 1 : 0)))); if (isForeignInliner) { sig.Append(new UnsignedConstant((uint)factory.ManifestMetadataTable.ModuleToIndex(inliner.Module))); } } hashtable.Append((uint)hashCode, section.Place(sig)); } MemoryStream writerContent = new MemoryStream(); writer.Save(writerContent); return(new ObjectData( data: writerContent.ToArray(), relocs: null, alignment: 8, definedSymbols: new ISymbolDefinitionNode[] { this })); }
public virtual bool CanInline(MethodDesc caller, MethodDesc callee) { // No restrictions on inlining by default return(true); }
public virtual MethodIL GetMethodIL(MethodDesc method) { return(_methodILCache.GetOrCreateValue(method).MethodIL); }
public abstract MethodProfileData GetMethodProfileData(MethodDesc m);
internal GVMDependenciesNode GVMDependencies(MethodDesc method) { return(_gvmDependenciesNode.GetOrAdd(method)); }