예제 #1
0
 internal IEnumerable <DelegateMarshallingThunks> GetDelegateMarshallingThunks()
 {
     foreach (var delegateType in _delegateMarshalingTypes)
     {
         yield return
             (new DelegateMarshallingThunks()
         {
             DelegateType = delegateType,
             OpenStaticDelegateMarshallingThunk = InteropStateManager.GetOpenStaticDelegateMarshallingThunk(delegateType),
             ClosedDelegateMarshallingThunk = InteropStateManager.GetClosedDelegateMarshallingThunk(delegateType),
             DelegateCreationThunk = InteropStateManager.GetForwardDelegateCreationThunk(delegateType)
         });
     }
 }
예제 #2
0
 internal IEnumerable <StructMarshallingThunks> GetStructMarshallingTypes()
 {
     foreach (var structType in _structMarshallingTypes)
     {
         yield return
             (new StructMarshallingThunks()
         {
             StructType = structType,
             NativeStructType = InteropStateManager.GetStructMarshallingNativeType(structType),
             MarshallingThunk = InteropStateManager.GetStructMarshallingManagedToNativeThunk(structType),
             UnmarshallingThunk = InteropStateManager.GetStructMarshallingNativeToManagedThunk(structType),
             CleanupThunk = InteropStateManager.GetStructMarshallingCleanupThunk(structType)
         });
     }
 }
예제 #3
0
        protected override void TransformNativeToManaged(ILCodeStream codeStream)
        {
            ILEmitter   emitter = _ilCodeStreams.Emitter;
            ILCodeLabel lNull   = emitter.NewCodeLabel();

            LoadManagedValue(codeStream);
            codeStream.Emit(ILOpcode.brfalse, lNull);

            LoadNativeValue(codeStream);
            LoadManagedValue(codeStream);
            codeStream.Emit(ILOpcode.call, _ilCodeStreams.Emitter.NewToken(
                                InteropStateManager.GetStructMarshallingNativeToManagedThunk(ManagedType)));

            codeStream.EmitLabel(lNull);
        }
예제 #4
0
        public override IEnumerable <DependencyListEntry> GetStaticDependencies(NodeFactory factory)
        {
            InteropStateManager stateManager = ((CompilerGeneratedInteropStubManager)factory.InteropStubManager)._interopStateManager;

            yield return(new DependencyListEntry(factory.NecessaryTypeSymbol(_type), "Struct Marshalling Stub"));

            // Not all StructMarshalingDataNodes require marshalling - some are only present because we want to
            // generate field offset information for Marshal.OffsetOf.
            if (MarshalHelpers.IsStructMarshallingRequired(_type))
            {
                yield return(new DependencyListEntry(factory.MethodEntrypoint(stateManager.GetStructMarshallingManagedToNativeThunk(_type)), "Struct Marshalling stub"));

                yield return(new DependencyListEntry(factory.MethodEntrypoint(stateManager.GetStructMarshallingNativeToManagedThunk(_type)), "Struct Marshalling stub"));

                yield return(new DependencyListEntry(factory.MethodEntrypoint(stateManager.GetStructMarshallingCleanupThunk(_type)), "Struct Marshalling stub"));
            }
        }
예제 #5
0
        protected override void EmitCleanupManaged(ILCodeStream codeStream)
        {
            // Only do cleanup if it is IN
            if (!In)
            {
                return;
            }

            ILEmitter   emitter = _ilCodeStreams.Emitter;
            ILCodeLabel lNull   = emitter.NewCodeLabel();

            LoadManagedValue(codeStream);
            codeStream.Emit(ILOpcode.brfalse, lNull);

            LoadNativeValue(codeStream);
            codeStream.Emit(ILOpcode.call, emitter.NewToken(
                                InteropStateManager.GetStructMarshallingCleanupThunk(ManagedType)));

            codeStream.EmitLabel(lNull);
        }
예제 #6
0
 public static MethodIL EmitIL(MethodDesc method,
                               PInvokeILEmitterConfiguration pinvokeILEmitterConfiguration,
                               InteropStateManager interopStateManager)
 {
     try
     {
         return(new PInvokeILEmitter(method, pinvokeILEmitterConfiguration, interopStateManager)
                .EmitIL());
     }
     catch (NotSupportedException)
     {
         string message = "Method '" + method.ToString() +
                          "' requires non-trivial marshalling that is not yet supported by this compiler.";
         return(MarshalHelpers.EmitExceptionBody(message, method));
     }
     catch (InvalidProgramException ex)
     {
         Debug.Assert(!String.IsNullOrEmpty(ex.Message));
         return(MarshalHelpers.EmitExceptionBody(ex.Message, method));
     }
 }
예제 #7
0
        protected override void AllocManagedToNative(ILCodeStream codeStream)
        {
            ILEmitter   emitter = _ilCodeStreams.Emitter;
            ILCodeLabel lNull   = emitter.NewCodeLabel();

            codeStream.EmitLdc(0);
            codeStream.Emit(ILOpcode.conv_i);
            StoreNativeValue(codeStream);

            LoadManagedValue(codeStream);
            codeStream.Emit(ILOpcode.brfalse, lNull);

            TypeDesc nativeStructType = InteropStateManager.GetStructMarshallingNativeType(ManagedType);

            ILLocalVariable lNativeType = emitter.NewLocal(nativeStructType);

            codeStream.EmitLdLoca(lNativeType);
            codeStream.Emit(ILOpcode.initobj, emitter.NewToken(nativeStructType));
            codeStream.EmitLdLoca(lNativeType);
            StoreNativeValue(codeStream);

            codeStream.EmitLabel(lNull);
        }
예제 #8
0
        private PInvokeILEmitter(MethodDesc targetMethod, PInvokeILEmitterConfiguration pinvokeILEmitterConfiguration, InteropStateManager interopStateManager)
        {
            Debug.Assert(targetMethod.IsPInvoke || targetMethod is DelegateMarshallingMethodThunk || targetMethod is CalliMarshallingMethodThunk);
            _targetMethod = targetMethod;
            _pInvokeILEmitterConfiguration = pinvokeILEmitterConfiguration;
            _pInvokeMetadata     = targetMethod.GetPInvokeMethodMetadata();
            _interopStateManager = interopStateManager;

            //
            // targetMethod could be either a PInvoke or a DelegateMarshallingMethodThunk
            // ForwardNativeFunctionWrapper method thunks are marked as PInvokes, so it is
            // important to check them first here so that we get the right flags.
            //
            if (_targetMethod is DelegateMarshallingMethodThunk delegateMethod)
            {
                _flags = ((EcmaType)delegateMethod.DelegateType.GetTypeDefinition()).GetDelegatePInvokeFlags();
            }
            else
            {
                _flags = _pInvokeMetadata.Flags;
            }
            _marshallers = InitializeMarshallers(targetMethod, interopStateManager, _flags);
        }
예제 #9
0
        protected override void TransformNativeToManaged(ILCodeStream codeStream)
        {
            ILEmitter   emitter  = _ilCodeStreams.Emitter;
            ILCodeLabel lNonNull = emitter.NewCodeLabel();

            LoadManagedValue(codeStream);
            codeStream.Emit(ILOpcode.brtrue, lNonNull);

            MethodDesc ctor = ManagedType.GetParameterlessConstructor();

            if (ctor == null)
            {
                throw new InvalidProgramException();
            }

            codeStream.Emit(ILOpcode.newobj, emitter.NewToken(ctor));
            StoreManagedValue(codeStream);

            codeStream.EmitLabel(lNonNull);
            LoadNativeAddr(codeStream);
            LoadManagedValue(codeStream);
            codeStream.Emit(ILOpcode.call, _ilCodeStreams.Emitter.NewToken(
                                InteropStateManager.GetStructMarshallingNativeToManagedThunk(ManagedType)));
        }
예제 #10
0
        internal static TypeDesc GetNativeStructFieldType(TypeDesc type, MarshalAsDescriptor marshalAs, InteropStateManager interopStateManager, bool isAnsi)
        {
            MarshallerKind elementMarshallerKind;
            MarshallerKind marshallerKind = MarshalHelpers.GetMarshallerKind(type,
                                                                             marshalAs,
                                                                             false,  /*  isReturn */
                                                                             isAnsi, /*    isAnsi */
                                                                             MarshallerType.Field,
                                                                             out elementMarshallerKind);

            return(GetNativeTypeFromMarshallerKind(type,
                                                   marshallerKind,
                                                   elementMarshallerKind,
                                                   interopStateManager,
                                                   marshalAs));
        }
예제 #11
0
        internal static TypeDesc GetNativeMethodParameterType(TypeDesc type, MarshalAsDescriptor marshalAs, InteropStateManager interopStateManager, bool isReturn, bool isAnsi)
        {
            MarshallerKind elementMarshallerKind;
            MarshallerKind marshallerKind = MarshalHelpers.GetMarshallerKind(type,
                                                                             marshalAs,
                                                                             isReturn,
                                                                             isAnsi,
                                                                             MarshallerType.Argument,
                                                                             out elementMarshallerKind);

            return(GetNativeTypeFromMarshallerKind(type,
                                                   marshallerKind,
                                                   elementMarshallerKind,
                                                   interopStateManager,
                                                   marshalAs));
        }
예제 #12
0
        private PInvokeILEmitter(MethodDesc targetMethod, PInvokeILEmitterConfiguration pinvokeILEmitterConfiguration, InteropStateManager interopStateManager)
        {
            Debug.Assert(targetMethod.IsPInvoke || targetMethod is DelegateMarshallingMethodThunk);
            _targetMethod = targetMethod;
            _pInvokeILEmitterConfiguration = pinvokeILEmitterConfiguration;
            _importMetadata      = targetMethod.GetPInvokeMethodMetadata();
            _interopStateManager = interopStateManager;

            PInvokeFlags flags = new PInvokeFlags();

            if (targetMethod.IsPInvoke)
            {
                flags = _importMetadata.Flags;
            }
            else
            {
                var delegateType = ((DelegateMarshallingMethodThunk)_targetMethod).DelegateType as EcmaType;
                if (delegateType != null)
                {
                    flags = delegateType.GetDelegatePInvokeFlags();
                }
            }

            _marshallers = InitializeMarshallers(targetMethod, interopStateManager, flags);
        }
예제 #13
0
 public InteropStubManager(CompilationModuleGroup compilationModuleGroup, CompilerTypeSystemContext typeSystemContext, InteropStateManager interopStateManager)
 {
     _compilationModuleGroup = compilationModuleGroup;
     _typeSystemContext      = typeSystemContext;
     InteropStateManager     = interopStateManager;
 }
예제 #14
0
 public AnalysisBasedInteropStubManager GetInteropStubManager(InteropStateManager stateManager, PInvokeILEmitterConfiguration pinvokePolicy)
 {
     return(new AnalysisBasedInteropStubManager(stateManager, pinvokePolicy,
                                                _factory.MetadataManager.GetTypesWithStructMarshalling(),
                                                _factory.MetadataManager.GetTypesWithDelegateMarshalling()));
 }
예제 #15
0
        private static                                 Marshaller[] InitializeMarshallers(MethodDesc targetMethod, InteropStateManager interopStateManager, PInvokeFlags flags)
        {
            bool             isDelegate = targetMethod is DelegateMarshallingMethodThunk;
            MethodSignature  methodSig  = isDelegate ? ((DelegateMarshallingMethodThunk)targetMethod).DelegateSignature : targetMethod.Signature;
            MarshalDirection direction  = isDelegate ? ((DelegateMarshallingMethodThunk)targetMethod).Direction: MarshalDirection.Forward;
            int indexOffset             = 0;

            if (!methodSig.IsStatic && direction == MarshalDirection.Forward)
            {
                // For instance methods(eg. Forward delegate marshalling thunk), first argument is
                // the instance
                indexOffset = 1;
            }
            ParameterMetadata[] parameterMetadataArray = targetMethod.GetParameterMetadata();
            Marshaller[]        marshallers            = new Marshaller[methodSig.Length + 1];
            int parameterIndex = 0;
            ParameterMetadata parameterMetadata;

            for (int i = 0; i < marshallers.Length; i++)
            {
                Debug.Assert(parameterIndex == parameterMetadataArray.Length || i <= parameterMetadataArray[parameterIndex].Index);
                if (parameterIndex == parameterMetadataArray.Length || i < parameterMetadataArray[parameterIndex].Index)
                {
                    // if we don't have metadata for the parameter, create a dummy one
                    parameterMetadata = new ParameterMetadata(i, ParameterMetadataAttributes.None, null);
                }
                else
                {
                    Debug.Assert(i == parameterMetadataArray[parameterIndex].Index);
                    parameterMetadata = parameterMetadataArray[parameterIndex++];
                }
                TypeDesc parameterType = (i == 0) ? methodSig.ReturnType : methodSig[i - 1];  //first item is the return type
                marshallers[i] = Marshaller.CreateMarshaller(parameterType,
                                                             MarshallerType.Argument,
                                                             parameterMetadata.MarshalAsDescriptor,
                                                             direction,
                                                             marshallers,
                                                             interopStateManager,
                                                             indexOffset + parameterMetadata.Index,
                                                             flags,
                                                             parameterMetadata.In,
                                                             parameterMetadata.Out,
                                                             parameterMetadata.Return
                                                             );
            }

            return(marshallers);
        }
예제 #16
0
 public StructMarshallingThunk(TypeDesc owningType, MetadataType managedType, StructMarshallingThunkType thunkType, InteropStateManager interopStateManager)
 {
     _owningType          = owningType;
     ManagedType          = managedType;
     _interopStateManager = interopStateManager;
     NativeType           = _interopStateManager.GetStructMarshallingNativeType(managedType);
     ThunkType            = thunkType;
 }
예제 #17
0
파일: Program.cs 프로젝트: heniu75/corert
        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");
            }

            if (_instructionSet != null)
            {
                List <string> instructionSetParams = new List <string>();

                // Normalize instruction set format to include implied +.
                string[] instructionSetParamsInput = _instructionSet.Split(',');
                for (int i = 0; i < instructionSetParamsInput.Length; i++)
                {
                    string instructionSet = instructionSetParamsInput[i];

                    if (String.IsNullOrEmpty(instructionSet))
                    {
                        throw new CommandLineException("Instruction set must not be empty");
                    }

                    char firstChar = instructionSet[0];
                    if ((firstChar != '+') && (firstChar != '-'))
                    {
                        instructionSet = "+" + instructionSet;
                    }
                    instructionSetParams.Add(instructionSet);
                }

                Dictionary <string, bool> instructionSetSpecification = new Dictionary <string, bool>();
                foreach (string instructionSetSpecifier in instructionSetParams)
                {
                    string instructionSet = instructionSetSpecifier.Substring(1, instructionSetSpecifier.Length - 1);

                    bool enabled = instructionSetSpecifier[0] == '+' ? true : false;
                    if (enabled)
                    {
                        if (!instructionSetSupportBuilder.AddSupportedInstructionSet(instructionSet))
                        {
                            throw new CommandLineException($"Unrecognized instruction set '{instructionSet}'");
                        }
                    }
                    else
                    {
                        if (!instructionSetSupportBuilder.RemoveInstructionSetSupport(instructionSet))
                        {
                            throw new CommandLineException($"Unrecognized instruction set '{instructionSet}'");
                        }
                    }
                }
            }

            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.
                //
                // The compiler is able to generate runtime IsSupported checks for the following instruction sets.
                optimisticInstructionSetSupportBuilder.AddSupportedInstructionSet("ssse3");
                optimisticInstructionSetSupportBuilder.AddSupportedInstructionSet("aes");
                optimisticInstructionSetSupportBuilder.AddSupportedInstructionSet("pclmul");
                optimisticInstructionSetSupportBuilder.AddSupportedInstructionSet("lzcnt");

                // NOTE: we don't optimistically enable SSE4.1/SSE4.2 because RyuJIT can opportunistically use
                // these instructions in e.g. optimizing Math.Round or Vector<T> operations without IsSupported guards.

                // If SSE4.2 was enabled, we can also opportunistically enable POPCNT
                Debug.Assert(InstructionSet.X64_SSE42 == InstructionSet.X86_SSE42);
                if (supportedInstructionSet.HasInstructionSet(InstructionSet.X64_SSE42))
                {
                    optimisticInstructionSetSupportBuilder.AddSupportedInstructionSet("popcnt");
                }

                // If AVX was enabled, we can opportunistically enable FMA/BMI
                Debug.Assert(InstructionSet.X64_AVX == InstructionSet.X86_AVX);
                if (supportedInstructionSet.HasInstructionSet(InstructionSet.X64_AVX))
                {
                    optimisticInstructionSetSupportBuilder.AddSupportedInstructionSet("fma");
                    optimisticInstructionSetSupportBuilder.AddSupportedInstructionSet("bmi1");
                    optimisticInstructionSetSupportBuilder.AddSupportedInstructionSet("bmi2");
                }
            }

            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));
                    compilationRoots.Add(new ExpectedIsaFeaturesRootProvider(instructionSetSupport));
                }

                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));
                    compilationRoots.Add(new ExpectedIsaFeaturesRootProvider(instructionSetSupport));
                }

                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;

            // Enable static data preinitialization in optimized builds.
            bool preinitStatics = _preinitStatics ||
                                  (_optimizationMode != OptimizationMode.None && !_isCppCodegen && !_multiFile);

            preinitStatics &= !_noPreinitStatics;

            var preinitManager = new PreinitializationManager(typeSystemContext, compilationGroup, ilProvider, preinitStatics);

            builder
            .UseILProvider(ilProvider)
            .UsePreinitializationManager(preinitManager);

            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" || method.Name == "ThrowArgumentOutOfRangeException");
                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();
            }

            preinitManager.LogStatistics(logger);

            return(0);
        }
예제 #18
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;
            }

            bool supportsReflection = !_disableReflection && _systemModuleName == DefaultSystemModule;

            //
            // Initialize type system context
            //

            SharedGenericsMode genericsMode = _useSharedGenerics || !_isWasmCodegen ?
                                              SharedGenericsMode.CanonicalReferenceTypes : SharedGenericsMode.Disabled;

            // TODO: compiler switch for SIMD support?
            var simdVectorLength = (_isCppCodegen || _isWasmCodegen) ? SimdVectorLength.None : SimdVectorLength.Vector128Bit;
            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;

            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 == "CurlHandler")
                {
                    removedFeatures |= RemovedFeature.CurlHandler;
                }
            }

            ILProvider ilProvider = new CoreRTILProvider();

            if (removedFeatures != 0)
            {
                ilProvider = new RemovingILProvider(ilProvider, removedFeatures);
            }

            var stackTracePolicy = _emitStackTraceData ?
                                   (StackTraceEmissionPolicy) new EcmaMethodStackTraceEmissionPolicy() : new NoStackTraceEmissionPolicy();

            MetadataBlockingPolicy mdBlockingPolicy = _noMetadataBlocking
                    ? (MetadataBlockingPolicy) new NoMetadataBlockingPolicy()
                    : new BlockedInternalsBlockingPolicy(typeSystemContext);

            ManifestResourceBlockingPolicy resBlockingPolicy = (removedFeatures & RemovedFeature.FrameworkResources) != 0 ?
                                                               new FrameworkStringResourceBlockingPolicy() : (ManifestResourceBlockingPolicy) new NoManifestResourceBlockingPolicy();

            UsageBasedMetadataGenerationOptions metadataGenerationOptions = UsageBasedMetadataGenerationOptions.AnonymousTypeHeuristic;

            if (_completeTypesMetadata)
            {
                metadataGenerationOptions |= UsageBasedMetadataGenerationOptions.CompleteTypesOnly;
            }
            if (_scanReflection)
            {
                metadataGenerationOptions |= UsageBasedMetadataGenerationOptions.ILScanning;
            }
            if (_rootAllApplicationAssemblies)
            {
                metadataGenerationOptions |= UsageBasedMetadataGenerationOptions.FullUserAssemblyRooting;
            }

            DynamicInvokeThunkGenerationPolicy invokeThunkGenerationPolicy = new DefaultDynamicInvokeThunkGenerationPolicy();

            MetadataManager metadataManager;

            if (supportsReflection)
            {
                metadataManager = new UsageBasedMetadataManager(
                    compilationGroup,
                    typeSystemContext,
                    mdBlockingPolicy,
                    resBlockingPolicy,
                    _metadataLogFileName,
                    stackTracePolicy,
                    invokeThunkGenerationPolicy,
                    ilProvider,
                    metadataGenerationOptions);
            }
            else
            {
                metadataManager = new EmptyMetadataManager(typeSystemContext, stackTracePolicy, ilProvider);
            }

            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();

                if (metadataManager is UsageBasedMetadataManager usageBasedManager)
                {
                    metadataManager = usageBasedManager.ToAnalysisBasedMetadataManager();
                }
                else
                {
                    // MetadataManager collects a bunch of state (e.g. list of compiled method bodies) that we need to reset.
                    Debug.Assert(metadataManager is EmptyMetadataManager);
                    metadataManager = new EmptyMetadataManager(typeSystemContext, stackTracePolicy, ilProvider);
                }

                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
            .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)
            {
                SimdHelper simdHelper = new SimdHelper();

                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) || simdHelper.IsSimdType(method.OwningType));
                    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);
        }
 public AnalysisBasedInteropStubManager(InteropStateManager interopStateManager, PInvokeILEmitterConfiguration pInvokeILEmitterConfiguration, IEnumerable <DefType> typesWithStructMarshalling, IEnumerable <DefType> typesWithDelegateMarshalling)
     : base(interopStateManager, pInvokeILEmitterConfiguration)
 {
     _typesWithStructMarshalling   = typesWithStructMarshalling;
     _typesWithDelegateMarshalling = typesWithDelegateMarshalling;
 }
예제 #20
0
 public PInvokeILProvider(PInvokeILEmitterConfiguration pInvokeILEmitterConfiguration, InteropStateManager interopStateManager)
 {
     _pInvokeILEmitterConfiguration = pInvokeILEmitterConfiguration;
     _interopStateManager           = interopStateManager;
 }
예제 #21
0
        private static                                 Marshaller[] InitializeMarshallers(MethodDesc targetMethod, InteropStateManager interopStateManager, PInvokeFlags flags)
        {
            MarshalDirection direction = MarshalDirection.Forward;
            MethodSignature  methodSig;

            switch (targetMethod)
            {
            case DelegateMarshallingMethodThunk delegateMethod:
                methodSig = delegateMethod.DelegateSignature;
                direction = delegateMethod.Direction;
                break;

            case CalliMarshallingMethodThunk calliMethod:
                methodSig = calliMethod.TargetSignature;
                break;

            default:
                methodSig = targetMethod.Signature;
                break;
            }
            int indexOffset = 0;

            if (!methodSig.IsStatic && direction == MarshalDirection.Forward)
            {
                // For instance methods(eg. Forward delegate marshalling thunk), first argument is
                // the instance
                indexOffset = 1;
            }
            ParameterMetadata[] parameterMetadataArray = targetMethod.GetParameterMetadata();
            Marshaller[]        marshallers            = new Marshaller[methodSig.Length + 1];
            int parameterIndex = 0;
            ParameterMetadata parameterMetadata;

            for (int i = 0; i < marshallers.Length; i++)
            {
                Debug.Assert(parameterIndex == parameterMetadataArray.Length || i <= parameterMetadataArray[parameterIndex].Index);
                if (parameterIndex == parameterMetadataArray.Length || i < parameterMetadataArray[parameterIndex].Index)
                {
                    // if we don't have metadata for the parameter, create a dummy one
                    parameterMetadata = new ParameterMetadata(i, ParameterMetadataAttributes.None, null);
                }
                else
                {
                    Debug.Assert(i == parameterMetadataArray[parameterIndex].Index);
                    parameterMetadata = parameterMetadataArray[parameterIndex++];
                }

                TypeDesc parameterType;
                bool     isHRSwappedRetVal = false;
                if (i == 0)
                {
                    // First item is the return type
                    parameterType = methodSig.ReturnType;
                    if (!flags.PreserveSig && !parameterType.IsVoid)
                    {
                        // PreserveSig = false can only show up an regular forward PInvokes
                        Debug.Assert(direction == MarshalDirection.Forward);

                        parameterType     = methodSig.Context.GetByRefType(parameterType);
                        isHRSwappedRetVal = true;
                    }
                }
                else
                {
                    parameterType = methodSig[i - 1];
                }

                marshallers[i] = Marshaller.CreateMarshaller(parameterType,
                                                             parameterIndex,
                                                             methodSig.GetEmbeddedSignatureData(),
                                                             MarshallerType.Argument,
                                                             parameterMetadata.MarshalAsDescriptor,
                                                             direction,
                                                             marshallers,
                                                             interopStateManager,
                                                             indexOffset + parameterMetadata.Index,
                                                             flags,
                                                             parameterMetadata.In,
                                                             isHRSwappedRetVal ? true : parameterMetadata.Out,
                                                             isHRSwappedRetVal ? false : parameterMetadata.Return
                                                             );
            }

            return(marshallers);
        }
예제 #22
0
        internal static TypeDesc GetNativeTypeFromMarshallerKind(TypeDesc type,
                                                                 MarshallerKind kind,
                                                                 MarshallerKind elementMarshallerKind,
                                                                 InteropStateManager interopStateManager,
                                                                 MarshalAsDescriptor marshalAs,
                                                                 bool isArrayElement = false)
        {
            TypeSystemContext context    = type.Context;
            NativeTypeKind    nativeType = NativeTypeKind.Invalid;

            if (marshalAs != null)
            {
                nativeType = isArrayElement ? marshalAs.ArraySubType : marshalAs.Type;
            }

            switch (kind)
            {
            case MarshallerKind.BlittableValue:
            {
                switch (nativeType)
                {
                case NativeTypeKind.I1:
                    return(context.GetWellKnownType(WellKnownType.SByte));

                case NativeTypeKind.U1:
                    return(context.GetWellKnownType(WellKnownType.Byte));

                case NativeTypeKind.I2:
                    return(context.GetWellKnownType(WellKnownType.Int16));

                case NativeTypeKind.U2:
                    return(context.GetWellKnownType(WellKnownType.UInt16));

                case NativeTypeKind.I4:
                    return(context.GetWellKnownType(WellKnownType.Int32));

                case NativeTypeKind.U4:
                    return(context.GetWellKnownType(WellKnownType.UInt32));

                case NativeTypeKind.I8:
                    return(context.GetWellKnownType(WellKnownType.Int64));

                case NativeTypeKind.U8:
                    return(context.GetWellKnownType(WellKnownType.UInt64));

                case NativeTypeKind.R4:
                    return(context.GetWellKnownType(WellKnownType.Single));

                case NativeTypeKind.R8:
                    return(context.GetWellKnownType(WellKnownType.Double));

                default:
                    return(type.UnderlyingType);
                }
            }

            case MarshallerKind.Bool:
                return(context.GetWellKnownType(WellKnownType.Int32));

            case MarshallerKind.CBool:
                return(context.GetWellKnownType(WellKnownType.Byte));

            case MarshallerKind.Enum:
            case MarshallerKind.BlittableStruct:
            case MarshallerKind.Decimal:
            case MarshallerKind.VoidReturn:
                return(type);

            case MarshallerKind.Struct:
                return(interopStateManager.GetStructMarshallingNativeType((MetadataType)type));

            case MarshallerKind.BlittableStructPtr:
                return(type.MakePointerType());

            case MarshallerKind.HandleRef:
                return(context.GetWellKnownType(WellKnownType.IntPtr));

            case MarshallerKind.UnicodeChar:
                if (nativeType == NativeTypeKind.U2)
                {
                    return(context.GetWellKnownType(WellKnownType.UInt16));
                }
                else
                {
                    return(context.GetWellKnownType(WellKnownType.Int16));
                }

            case MarshallerKind.OleDateTime:
                return(context.GetWellKnownType(WellKnownType.Double));

            case MarshallerKind.SafeHandle:
            case MarshallerKind.CriticalHandle:
                return(context.GetWellKnownType(WellKnownType.IntPtr));

            case MarshallerKind.UnicodeString:
            case MarshallerKind.UnicodeStringBuilder:
                return(context.GetWellKnownType(WellKnownType.Char).MakePointerType());

            case MarshallerKind.AnsiString:
            case MarshallerKind.AnsiStringBuilder:
                return(context.GetWellKnownType(WellKnownType.Byte).MakePointerType());

            case MarshallerKind.BlittableArray:
            case MarshallerKind.Array:
            case MarshallerKind.AnsiCharArray:
            {
                ArrayType arrayType = type as ArrayType;
                Debug.Assert(arrayType != null, "Expecting array");

                //
                // We need to construct the unsafe array from the right unsafe array element type
                //
                TypeDesc elementNativeType = GetNativeTypeFromMarshallerKind(
                    arrayType.ElementType,
                    elementMarshallerKind,
                    MarshallerKind.Unknown,
                    interopStateManager,
                    marshalAs,
                    isArrayElement: true);

                return(elementNativeType.MakePointerType());
            }

            case MarshallerKind.AnsiChar:
                return(context.GetWellKnownType(WellKnownType.Byte));

            case MarshallerKind.FunctionPointer:
                return(context.GetWellKnownType(WellKnownType.IntPtr));

            case MarshallerKind.ByValUnicodeString:
            case MarshallerKind.ByValAnsiString:
            {
                var inlineArrayCandidate = GetInlineArrayCandidate(context.GetWellKnownType(WellKnownType.Char), elementMarshallerKind, interopStateManager, marshalAs);
                return(interopStateManager.GetInlineArrayType(inlineArrayCandidate));
            }

            case MarshallerKind.ByValAnsiCharArray:
            case MarshallerKind.ByValArray:
            {
                ArrayType arrayType = type as ArrayType;
                Debug.Assert(arrayType != null, "Expecting array");

                var inlineArrayCandidate = GetInlineArrayCandidate(arrayType.ElementType, elementMarshallerKind, interopStateManager, marshalAs);

                return(interopStateManager.GetInlineArrayType(inlineArrayCandidate));
            }

            case MarshallerKind.Unknown:
            default:
                throw new NotSupportedException();
            }
        }
예제 #23
0
        internal static InlineArrayCandidate GetInlineArrayCandidate(TypeDesc managedElementType, MarshallerKind elementMarshallerKind, InteropStateManager interopStateManager, MarshalAsDescriptor marshalAs)
        {
            TypeDesc nativeType = GetNativeTypeFromMarshallerKind(
                managedElementType,
                elementMarshallerKind,
                MarshallerKind.Unknown,
                interopStateManager,
                null);

            var elementNativeType = nativeType as MetadataType;

            if (elementNativeType == null)
            {
                Debug.Assert(nativeType.IsPointer || nativeType.IsFunctionPointer);

                // If it is a pointer type we will create InlineArray for IntPtr
                elementNativeType = (MetadataType)managedElementType.Context.GetWellKnownType(WellKnownType.IntPtr);
            }
            Debug.Assert(marshalAs != null && marshalAs.SizeConst.HasValue);

            // if SizeConst is not specified, we will default to 1.
            // the marshaller will throw appropriate exception
            uint size = 1;

            if (marshalAs.SizeConst.HasValue)
            {
                size = marshalAs.SizeConst.Value;
            }
            return(new InlineArrayCandidate(elementNativeType, size));
        }
        private TypeDesc GetNativeMethodParameterType(TypeDesc managedType, MarshalAsDescriptor marshalAs, InteropStateManager interopStateManager, bool isReturn, bool isAnsi)
        {
            TypeDesc nativeType;

            try
            {
                nativeType = MarshalHelpers.GetNativeMethodParameterType(managedType, marshalAs, interopStateManager, isReturn, isAnsi);
            }
            catch (NotSupportedException)
            {
                // if marshalling is not supported for this type the generated stubs will emit appropriate
                // error message. We just set native type to be same as managedtype
                nativeType = managedType;
            }
            return(nativeType);
        }
예제 #25
0
        public PInvokeDelegateWrapper(ModuleDesc owningModule, MetadataType delegateType, InteropStateManager interopStateManager)
        {
            Debug.Assert(delegateType.IsDelegate);

            Module               = owningModule;
            DelegateType         = delegateType;
            _interopStateManager = interopStateManager;
        }
 public CompilerGeneratedInteropStubManager(InteropStateManager interopStateManager, PInvokeILEmitterConfiguration pInvokeILEmitterConfiguration)
 {
     _interopStateManager           = interopStateManager;
     _pInvokeILEmitterConfiguration = pInvokeILEmitterConfiguration;
 }
예제 #27
0
 public ForwardDelegateCreationThunk(MetadataType delegateType, TypeDesc owningType, InteropStateManager interopStateManager)
 {
     _owningType          = owningType;
     _delegateType        = delegateType;
     _interopStateManager = interopStateManager;
 }
예제 #28
0
        public InteropStubManager(CompilationModuleGroup compilationModuleGroup, CompilerTypeSystemContext typeSystemContext, InteropStateManager interopStateManager)
        {
            _compilationModuleGroup = compilationModuleGroup;
            _typeSystemContext      = typeSystemContext;
            InteropStateManager     = interopStateManager;

            // Note: interopModule might be null if we're building with a class library that doesn't support rich interop
            _interopModule = typeSystemContext.GetModuleForSimpleName(_interopModuleName, false);
        }
예제 #29
0
        public NativeStructType(ModuleDesc owningModule, MetadataType managedStructType, InteropStateManager interopStateManager)
        {
            Debug.Assert(managedStructType.IsTypeDefinition);
            Debug.Assert(managedStructType.IsValueType);
            Debug.Assert(!managedStructType.IsGenericDefinition);

            Module               = owningModule;
            ManagedStructType    = managedStructType;
            _interopStateManager = interopStateManager;
            _hasInvalidLayout    = false;
            CalculateFields();
        }
예제 #30
0
 public CompilerGeneratedInteropStubManager(CompilationModuleGroup compilationModuleGroup, CompilerTypeSystemContext typeSystemContext, InteropStateManager interopStateManager) :
     base(compilationModuleGroup, typeSystemContext, interopStateManager)
 {
 }