Exemplo n.º 1
0
 public IMethodNode ShadowConcreteMethod(MethodDesc method, bool isUnboxingStub = false)
 {
     return(_shadowConcreteMethods.GetOrAdd(new MethodKey(method, isUnboxingStub)));
 }
Exemplo n.º 2
0
        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));
        }
Exemplo n.º 3
0
        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);
        }
Exemplo n.º 4
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));
 }
Exemplo n.º 5
0
 public bool IsEffectivelySealed(MethodDesc method)
 {
     return(_devirtualizationManager.IsEffectivelySealed(method));
 }
Exemplo n.º 6
0
 public sealed override bool VersionsWithMethodBody(MethodDesc method)
 {
     return(_versionsWithMethodCache.GetOrAdd(method, VersionsWithMethodUncached));
 }
Exemplo n.º 7
0
 // Internal predicate so that the switches controlling cross module inlining and compilation are independent
 private bool CrossModuleInlineableInternal(MethodDesc method)
 {
     return(_crossModuleInlineableCache.GetOrAdd(method, CrossModuleInlineableUncached));
 }
Exemplo n.º 8
0
        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);
        }
Exemplo n.º 9
0
 protected override IMethodNode CreateUnboxingStubNode(MethodDesc method)
 {
     // TODO: this is wrong: this returns an assembly stub node
     return(new UnboxingStubNode(method));
 }
Exemplo n.º 10
0
 public MethodKey(MethodDesc method, bool isUnboxingStub)
 {
     Method         = method;
     IsUnboxingStub = isUnboxingStub;
 }
Exemplo n.º 11
0
 public DispatchCellKey(MethodDesc target, string callsiteId)
 {
     Target     = target;
     CallsiteId = callsiteId;
 }
Exemplo n.º 12
0
 public EmbeddedObjectNode EagerCctorIndirection(MethodDesc cctorMethod)
 {
     return(_eagerCctorIndirectionNodes.GetOrAdd(cctorMethod));
 }
Exemplo n.º 13
0
 public DependencyNodeCore <NodeFactory> VirtualMethodUse(MethodDesc decl)
 {
     return(_virtMethods.GetOrAdd(decl));
 }
Exemplo n.º 14
0
 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);
            }
        }
Exemplo n.º 16
0
    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);
    }
Exemplo n.º 17
0
 public ModuleToken GetModuleTokenForMethod(MethodDesc method, bool throwIfNotFound = true)
 {
     return(Resolver.GetModuleTokenForMethod(method, throwIfNotFound));
 }
Exemplo n.º 18
0
        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);
                }
            }
        }
Exemplo n.º 19
0
        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);
            }
        }
Exemplo n.º 20
0
        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();
        }
Exemplo n.º 21
0
 public sealed override bool GeneratesPInvoke(MethodDesc method)
 {
     return(!Marshaller.IsMarshallingRequired(method));
 }
Exemplo n.º 22
0
        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
            }
        }
Exemplo n.º 23
0
 /// <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"));
 }
Exemplo n.º 24
0
 /// <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"));
 }
Exemplo n.º 25
0
 public MethodDesc ResolveVirtualMethod(MethodDesc declMethod, TypeDesc implType)
 {
     return(_devirtualizationManager.ResolveVirtualMethod(declMethod, implType));
 }
Exemplo n.º 26
0
        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 }));
        }
Exemplo n.º 27
0
 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);
 }
Exemplo n.º 29
0
 public abstract MethodProfileData GetMethodProfileData(MethodDesc m);
Exemplo n.º 30
0
 internal GVMDependenciesNode GVMDependencies(MethodDesc method)
 {
     return(_gvmDependenciesNode.GetOrAdd(method));
 }