コード例 #1
0
            protected override MethodILData CreateValueFromKey(MethodDesc key)
            {
                MethodIL methodIL = ILProvider.GetMethodIL(key);

                if (methodIL == null &&
                    key.IsPInvoke &&
                    _compilationModuleGroup.GeneratesPInvoke(key))
                {
                    methodIL = PInvokeILEmitter.EmitIL(key);
                }

                return(new MethodILData()
                {
                    Method = key, MethodIL = methodIL
                });
            }
コード例 #2
0
            protected override MethodILData CreateValueFromKey(MethodDesc key)
            {
                MethodIL methodIL = ILProvider.GetMethodIL(key);

                if (methodIL == null &&
                    key.IsPInvoke &&
                    _compilationModuleGroup.GeneratesPInvoke(key))
                {
                    // TODO: enable when IL Stubs are fixed to be non-shared
                    // methodIL = PInvokeILEmitter.EmitIL(key);
                }

                return(new MethodILData()
                {
                    Method = key, MethodIL = methodIL
                });
            }
コード例 #3
0
ファイル: RyuJitCompilation.cs プロジェクト: tmds/corert
        protected override void ComputeDependencyNodeDependencies(List <DependencyNodeCore <NodeFactory> > obj)
        {
            foreach (DependencyNodeCore <NodeFactory> dependency in obj)
            {
                var methodCodeNodeNeedingCode = dependency as MethodCodeNode;
                if (methodCodeNodeNeedingCode == null)
                {
                    // To compute dependencies of the shadow method that tracks dictionary
                    // dependencies we need to ensure there is code for the canonical method body.
                    var dependencyMethod = (ShadowConcreteMethodNode)dependency;
                    methodCodeNodeNeedingCode = (MethodCodeNode)dependencyMethod.CanonicalMethodNode;
                }

                // We might have already compiled this method.
                if (methodCodeNodeNeedingCode.StaticDependenciesAreComputed)
                {
                    continue;
                }

                MethodDesc method = methodCodeNodeNeedingCode.Method;

                if (Logger.IsVerbose)
                {
                    string methodName = method.ToString();
                    Logger.Writer.WriteLine("Compiling " + methodName);
                }

                try
                {
                    _corInfo.CompileMethod(methodCodeNodeNeedingCode);
                }
                catch (TypeSystemException ex)
                {
                    // TODO: fail compilation if a switch was passed

                    // Try to compile the method again, but with a throwing method body this time.
                    MethodIL throwingIL = TypeSystemThrowingILEmitter.EmitIL(method, ex);
                    _corInfo.CompileMethod(methodCodeNodeNeedingCode, throwingIL);

                    // TODO: Log as a warning. For now, just log to the logger; but this needs to
                    // have an error code, be supressible, the method name/sig needs to be properly formatted, etc.
                    // https://github.com/dotnet/corert/issues/72
                    Logger.Writer.WriteLine($"Warning: Method `{method}` will always throw because: {ex.Message}");
                }
            }
        }
コード例 #4
0
        /// <summary>
        /// Skips over a "foo == typeof(Bar)" or "typeof(Foo) == typeof(Bar)" sequence.
        /// </summary>
        private static bool IsTypeEqualityTest(MethodIL methodIL, ILReader reader, out ILReader afterTest)
        {
            afterTest = default;

            if (reader.ReadILOpcode() != ILOpcode.call)
            {
                return(false);
            }
            MethodDesc method = methodIL.GetObject(reader.ReadILToken()) as MethodDesc;

            if (method == null || method.Name != "GetTypeFromHandle" && !method.OwningType.IsSystemType())
            {
                return(false);
            }

            ILOpcode opcode = reader.ReadILOpcode();

            if (opcode == ILOpcode.ldtoken)
            {
                reader.ReadILToken();
                opcode = reader.ReadILOpcode();
                if (opcode != ILOpcode.call)
                {
                    return(false);
                }
                method = methodIL.GetObject(reader.ReadILToken()) as MethodDesc;
                if (method == null || method.Name != "GetTypeFromHandle" && !method.OwningType.IsSystemType())
                {
                    return(false);
                }
                opcode = reader.ReadILOpcode();
            }
            if (opcode != ILOpcode.call)
            {
                return(false);
            }
            method = methodIL.GetObject(reader.ReadILToken()) as MethodDesc;
            if (method == null || method.Name != "op_Equality" && !method.OwningType.IsSystemType())
            {
                return(false);
            }

            afterTest = reader;
            return(true);
        }
コード例 #5
0
        public ReflectionPatternContext(
            Logger logger,
            bool reportingEnabled,
            TypeSystemEntity source,
            Origin memberWithRequirements)
        {
            _logger                = logger;
            ReportingEnabled       = reportingEnabled;
            Source                 = source;
            MemberWithRequirements = memberWithRequirements;
            _ilOffset              = 0;
            _sourceIL              = null;

#if DEBUG
            _patternAnalysisAttempted = false;
            _patternReported          = false;
#endif
        }
コード例 #6
0
        protected override void GetDependenciesDueToMethodCodePresence(ref DependencyNodeCore <NodeFactory> .DependencyList dependencies, NodeFactory factory, MethodDesc method)
        {
            if (_ilProvider != null)
            {
                MethodIL methodIL = _ilProvider.GetMethodIL(method);

                if (methodIL != null)
                {
                    try
                    {
                        ReflectionMethodBodyScanner.ScanMarshalOnly(ref dependencies, factory, methodIL);
                    }
                    catch (TypeSystemException)
                    {
                        // A problem with the IL - we just don't scan it...
                    }
                }
            }
        }
コード例 #7
0
        protected override void GetDependenciesDueToMethodCodePresenceInternal(ref DependencyList dependencies, NodeFactory factory, MethodDesc method)
        {
            if ((_generationOptions & UsageBasedMetadataGenerationOptions.ILScanning) != 0)
            {
                MethodIL methodIL = _ilProvider.GetMethodIL(method);

                if (methodIL != null)
                {
                    try
                    {
                        ReflectionMethodBodyScanner.Scan(ref dependencies, factory, methodIL);
                    }
                    catch (TypeSystemException)
                    {
                        // A problem with the IL - we just don't scan it...
                    }
                }
            }
        }
コード例 #8
0
        protected override void ComputeDependencyNodeDependencies(List <DependencyNodeCore <NodeFactory> > obj)
        {
            foreach (DependencyNodeCore <NodeFactory> dependency in obj)
            {
                var methodCodeNodeNeedingCode = dependency as MethodCodeNode;
                if (methodCodeNodeNeedingCode == null)
                {
                    // To compute dependencies of the shadow method that tracks dictionary
                    // dependencies we need to ensure there is code for the canonical method body.
                    var dependencyMethod = (ShadowConcreteMethodNode <MethodCodeNode>)dependency;
                    methodCodeNodeNeedingCode = dependencyMethod.CanonicalMethodNode;
                }

                // We might have already compiled this method.
                if (methodCodeNodeNeedingCode.StaticDependenciesAreComputed)
                {
                    continue;
                }

                MethodDesc method = methodCodeNodeNeedingCode.Method;

                if (Logger.IsVerbose)
                {
                    string methodName = method.ToString();
                    Logger.Writer.WriteLine("Compiling " + methodName);
                }

                try
                {
                    _corInfo.CompileMethod(methodCodeNodeNeedingCode);
                }
                catch (TypeSystemException ex)
                {
                    // TODO: fail compilation if a switch was passed

                    // Try to compile the method again, but with a throwing method body this time.
                    MethodIL throwingIL = TypeSystemThrowingILEmitter.EmitIL(method, ex);
                    _corInfo.CompileMethod(methodCodeNodeNeedingCode, throwingIL);

                    // TODO: Log as a warning
                }
            }
        }
コード例 #9
0
        private void CompileSingleMethod(CorInfoImpl corInfo, MethodCodeNode methodCodeNodeNeedingCode)
        {
            MethodDesc method = methodCodeNodeNeedingCode.Method;

            TypeSystemException exception = _methodImportationErrorProvider.GetCompilationError(method);

            // If we previously failed to import the method, do not try to import it again and go
            // directly to the error path.
            if (exception == null)
            {
                try
                {
                    corInfo.CompileMethod(methodCodeNodeNeedingCode);
                }
                catch (TypeSystemException ex)
                {
                    exception = ex;
                }
            }

            if (exception != null)
            {
                // Try to compile the method again, but with a throwing method body this time.
                MethodIL throwingIL = TypeSystemThrowingILEmitter.EmitIL(method, exception);
                corInfo.CompileMethod(methodCodeNodeNeedingCode, throwingIL);

                if (exception is TypeSystemException.InvalidProgramException &&
                    method.OwningType is MetadataType mdOwningType &&
                    mdOwningType.HasCustomAttribute("System.Runtime.InteropServices", "ClassInterfaceAttribute"))
                {
                    Logger.LogWarning(method, DiagnosticId.COMInteropNotSupportedInFullAOT);
                }
                if ((_compilationOptions & RyuJitCompilationOptions.UseResilience) != 0)
                {
                    Logger.LogMessage($"Method '{method}' will always throw because: {exception.Message}");
                }
                else
                {
                    Logger.LogError($"Method will always throw because: {exception.Message}", 1005, method, MessageSubCategory.AotAnalysis);
                }
            }
        }
コード例 #10
0
        private void CompileSingleMethod(CorInfoImpl corInfo, MethodCodeNode methodCodeNodeNeedingCode)
        {
            try
            {
                MethodDesc method = methodCodeNodeNeedingCode.Method;

                TypeSystemException exception = _methodImportationErrorProvider.GetCompilationError(method);

                // If we previously failed to import the method, do not try to import it again and go
                // directly to the error path.
                if (exception == null)
                {
                    try
                    {
                        corInfo.CompileMethod(methodCodeNodeNeedingCode);
                    }
                    catch (TypeSystemException ex)
                    {
                        exception = ex;
                    }
                }

                if (exception != null)
                {
                    // TODO: fail compilation if a switch was passed

                    // Try to compile the method again, but with a throwing method body this time.
                    MethodIL throwingIL = TypeSystemThrowingILEmitter.EmitIL(method, exception);
                    corInfo.CompileMethod(methodCodeNodeNeedingCode, throwingIL);

                    if (exception is TypeSystemException.InvalidProgramException &&
                        method.OwningType is MetadataType mdOwningType &&
                        mdOwningType.HasCustomAttribute("System.Runtime.InteropServices", "ClassInterfaceAttribute"))
                    {
                        Logger.LogWarning("COM interop is not supported with full ahead of time compilation", 3052, method, MessageSubCategory.AotAnalysis);
                    }
                    else
                    {
                        Logger.LogWarning($"Method will always throw because: {exception.Message}", 1005, method, MessageSubCategory.AotAnalysis);
                    }
                }
            }
コード例 #11
0
ファイル: ILScanner.cs プロジェクト: mikem8361/runtime
        private void CompileSingleMethod(ScannedMethodNode methodCodeNodeNeedingCode)
        {
            MethodDesc method = methodCodeNodeNeedingCode.Method;

            try
            {
                var importer = new ILImporter(this, method);
                methodCodeNodeNeedingCode.InitializeDependencies(_nodeFactory, importer.Import());
            }
            catch (TypeSystemException ex)
            {
                // Try to compile the method again, but with a throwing method body this time.
                MethodIL throwingIL = TypeSystemThrowingILEmitter.EmitIL(method, ex);
                var      importer   = new ILImporter(this, method, throwingIL);
                methodCodeNodeNeedingCode.InitializeDependencies(_nodeFactory, importer.Import(), ex);
            }
            catch (Exception ex)
            {
                throw new CodeGenerationFailedException(method, ex);
            }
        }
コード例 #12
0
ファイル: MethodBodyScanner.cs プロジェクト: z77ma/runtime
        private StackSlot PopUnknown(Stack <StackSlot> stack, int count, MethodIL method, int ilOffset)
        {
            if (count < 1)
            {
                throw new InvalidOperationException();
            }

            StackSlot topOfStack = default;

            CheckForInvalidStack(stack, count, method, ilOffset);

            for (int i = 0; i < count; ++i)
            {
                StackSlot slot = stack.Pop();
                if (i == 0)
                {
                    topOfStack = slot;
                }
            }
            return(topOfStack);
        }
コード例 #13
0
        public override MethodIL GetMethodIL(MethodDesc method)
        {
            BodySubstitution substitution = GetSubstitution(method);

            if (substitution != null)
            {
                return(substitution.EmitIL(method));
            }

            // BEGIN TEMPORARY WORKAROUND
            //
            // The following lines should just be:
            // return _nestedILProvider.GetMethodIL(method);
            // But we want to allow this to be used as a general-purpose IL provider.
            //
            // Rewriting all IL has compilation throughput hit we don't want.
            MethodIL result = _nestedILProvider.GetMethodIL(method);

            if (result != null)
            {
                var resultDef = result.GetMethodILDefinition();
                if (resultDef != result)
                {
                    MethodIL newBodyDef = GetMethodILWithInlinedSubstitutions(resultDef);

                    // If we didn't rewrite the body, we can keep the existing result.
                    if (newBodyDef != resultDef)
                    {
                        result = new InstantiatedMethodIL(method, newBodyDef);
                    }
                }
                else
                {
                    result = GetMethodILWithInlinedSubstitutions(result);
                }
            }
            return(result);
            // END TEMPORARY WORKAROUND
        }
コード例 #14
0
ファイル: MessageOrigin.cs プロジェクト: naricc/runtime
        public MessageOrigin(MethodIL origin, int ilOffset)
        {
            string document   = null;
            int?   lineNumber = null;

            IEnumerable <ILSequencePoint> sequencePoints = origin.GetDebugInfo()?.GetSequencePoints();

            if (sequencePoints != null)
            {
                foreach (var sequencePoint in sequencePoints)
                {
                    if (sequencePoint.Offset <= ilOffset)
                    {
                        document   = sequencePoint.Document;
                        lineNumber = sequencePoint.LineNumber;
                    }
                }
            }
            FileName         = document;
            MemberDefinition = origin.OwningMethod;
            SourceLine       = lineNumber;
            SourceColumn     = null;
        }
コード例 #15
0
ファイル: ILScanner.cs プロジェクト: zhenman-li/corert
        private void CompileSingleMethod(ScannedMethodNode methodCodeNodeNeedingCode)
        {
            MethodDesc method = methodCodeNodeNeedingCode.Method;

            try
            {
                var importer = new ILImporter(this, method);
                methodCodeNodeNeedingCode.InitializeDependencies(_nodeFactory, importer.Import());
            }
            catch (TypeSystemException ex)
            {
                // Try to compile the method again, but with a throwing method body this time.
                MethodIL throwingIL = TypeSystemThrowingILEmitter.EmitIL(method, ex);
                var      importer   = new ILImporter(this, method, throwingIL);
                methodCodeNodeNeedingCode.InitializeDependencies(_nodeFactory, importer.Import());
            }
            finally
            {
                if (_compilationCountdown != null)
                {
                    _compilationCountdown.Signal();
                }
            }
        }
コード例 #16
0
        public static HashSet <int> ComputeBranchTargets(this MethodIL methodBody)
        {
            HashSet <int> branchTargets = new HashSet <int>();
            var           reader        = new ILReader(methodBody.GetILBytes());

            while (reader.HasNext)
            {
                ILOpcode opcode = reader.ReadILOpcode();
                if (opcode >= ILOpcode.br_s && opcode <= ILOpcode.blt_un)
                {
                    branchTargets.Add(reader.ReadBranchDestination(opcode));
                }
                else if (opcode == ILOpcode.switch_)
                {
                    uint count   = reader.ReadILUInt32();
                    int  jmpBase = reader.Offset + (int)(4 * count);
                    for (uint i = 0; i < count; i++)
                    {
                        branchTargets.Add((int)reader.ReadILUInt32() + jmpBase);
                    }
                }
                else
                {
                    reader.Skip(opcode);
                }
            }
            foreach (ILExceptionRegion einfo in methodBody.GetExceptionRegions())
            {
                if (einfo.Kind == ILExceptionRegionKind.Filter)
                {
                    branchTargets.Add(einfo.FilterOffset);
                }
                branchTargets.Add(einfo.HandlerOffset);
            }
            return(branchTargets);
        }
コード例 #17
0
        private PerMethodInfo GetOrCreateInfo(MethodDesc md)
        {
            if (!_methodInf.TryGetValue(md, out PerMethodInfo pmi))
            {
                MethodIL il =
                    md switch
                {
                    EcmaMethod em => EcmaMethodIL.Create(em),
                    _ => new InstantiatedMethodIL(md, EcmaMethodIL.Create((EcmaMethod)md.GetTypicalMethodDefinition())),
                };

                if (il == null)
                {
                    return(null);
                }

                _methodInf.Add(md, pmi = new PerMethodInfo());
                pmi.IL        = il;
                pmi.FlowGraph = FlowGraph.Create(il);
                pmi.Profile   = new SampleProfile(pmi.IL, pmi.FlowGraph);
            }

            return(pmi);
        }
コード例 #18
0
        /// <summary>
        /// Subset of <see cref="Scan(ref DependencyList, NodeFactory, MethodIL)"/> that only deals with Marshal.SizeOf.
        /// </summary>
        public static void ScanMarshalOnly(ref DependencyList list, NodeFactory factory, MethodIL methodIL)
        {
            ILReader reader = new ILReader(methodIL.GetILBytes());

            Tracker tracker = new Tracker(methodIL);

            while (reader.HasNext)
            {
                ILOpcode opcode = reader.ReadILOpcode();
                switch (opcode)
                {
                case ILOpcode.ldtoken:
                    tracker.TrackLdTokenToken(reader.ReadILToken());
                    break;

                case ILOpcode.call:
                    var method = methodIL.GetObject(reader.ReadILToken()) as MethodDesc;
                    if (method != null && method.Name == "SizeOf" && IsMarshalSizeOf(method))
                    {
                        TypeDesc type = tracker.GetLastType();
                        if (IsTypeEligibleForMarshalSizeOfTracking(type))
                        {
                            list = list ?? new DependencyList();

                            list.Add(factory.StructMarshallingData((DefType)type), "Marshal.SizeOf");
                        }
                    }
                    break;

                default:
                    reader.Skip(opcode);
                    break;
                }
            }
        }
コード例 #19
0
        private static void HandleCall(ref DependencyList list, NodeFactory factory, MethodIL methodIL, MethodDesc methodCalled, ref Tracker tracker)
        {
            switch (methodCalled.Name)
            {
            // Enum.GetValues(Type) needs array of that type
            case "GetValues" when methodCalled.OwningType == factory.TypeSystemContext.GetWellKnownType(WellKnownType.Enum):
            {
                TypeDesc type = tracker.GetLastType();
                if (type != null && type.IsEnum && !type.IsGenericDefinition /* generic enums! */)
                {
                    // Type could be something weird like MyEnum<object, __Canon> - normalize it
                    type = type.NormalizeInstantiation();

                    list = list ?? new DependencyList();
                    list.Add(factory.ConstructedTypeSymbol(type.MakeArrayType()), "Enum.GetValues");
                }
            }
            break;

            // Type.GetType(string...) needs the type with the given name
            case "GetType" when methodCalled.OwningType.IsSystemType() && methodCalled.Signature.Length > 0:
            {
                string name = tracker.GetLastString();
                if (name != null &&
                    methodIL.OwningMethod.OwningType is MetadataType mdType &&
                    ResolveType(name, mdType.Module, out TypeDesc type, out ModuleDesc referenceModule) &&
                    !factory.MetadataManager.IsReflectionBlocked(type))
                {
                    const string reason = "Type.GetType";
                    list = list ?? new DependencyList();
                    list.Add(factory.MaximallyConstructableType(type), reason);

                    // Also add module metadata in case this reference was through a type forward
                    if (factory.MetadataManager.CanGenerateMetadata(referenceModule.GetGlobalModuleType()))
                    {
                        list.Add(factory.ModuleMetadata(referenceModule), reason);
                    }

                    // Opportunistically remember the type so that it flows to Type.GetMethod if needed.
                    tracker.TrackType(type);
                }
            }
            break;

            // Type.GetMethod(string...)
            case "GetMethod" when methodCalled.OwningType.IsSystemType():
            {
                string   name = tracker.GetLastString();
                TypeDesc type = tracker.GetLastType();
                if (name != null &&
                    type != null &&
                    !factory.MetadataManager.IsReflectionBlocked(type))
                {
                    if (type.IsGenericDefinition)
                    {
                        Instantiation inst = TypeExtensions.GetInstantiationThatMeetsConstraints(type.Instantiation, allowCanon: false);
                        if (inst.IsNull)
                        {
                            break;
                        }
                        type = ((MetadataType)type).MakeInstantiatedType(inst);
                        list = list ?? new DependencyList();
                        list.Add(factory.MaximallyConstructableType(type), "Type.GetMethod");
                    }
                    else
                    {
                        // Type could be something weird like SomeType<object, __Canon> - normalize it
                        type = type.NormalizeInstantiation();
                    }

                    MethodDesc reflectedMethod = type.GetMethod(name, null);
                    if (reflectedMethod != null &&
                        !factory.MetadataManager.IsReflectionBlocked(reflectedMethod))
                    {
                        if (reflectedMethod.HasInstantiation)
                        {
                            // Don't want to accidentally get Foo<__Canon>.Bar<object>()
                            if (reflectedMethod.OwningType.IsCanonicalSubtype(CanonicalFormKind.Any))
                            {
                                break;
                            }

                            Instantiation inst = TypeExtensions.GetInstantiationThatMeetsConstraints(reflectedMethod.Instantiation, allowCanon: false);
                            if (inst.IsNull)
                            {
                                break;
                            }
                            reflectedMethod = reflectedMethod.MakeInstantiatedMethod(inst);
                        }

                        const string reason = "Type.GetMethod";
                        list = list ?? new DependencyList();
                        if (reflectedMethod.IsVirtual)
                        {
                            RootVirtualMethodForReflection(ref list, factory, reflectedMethod, reason);
                        }

                        if (!reflectedMethod.IsAbstract)
                        {
                            list.Add(factory.CanonicalEntrypoint(reflectedMethod), reason);
                            if (reflectedMethod.HasInstantiation &&
                                reflectedMethod != reflectedMethod.GetCanonMethodTarget(CanonicalFormKind.Specific))
                            {
                                list.Add(factory.MethodGenericDictionary(reflectedMethod), reason);
                            }
                        }
                    }
                }
            }
            break;

            case "SizeOf" when IsMarshalSizeOf(methodCalled):
            {
                TypeDesc type = tracker.GetLastType();
                if (IsTypeEligibleForMarshalSizeOfTracking(type))
                {
                    list = list ?? new DependencyList();

                    list.Add(factory.StructMarshallingData((DefType)type), "Marshal.SizeOf");
                }
            }
            break;
            }
        }
コード例 #20
0
 public MethodDebugInformation GetDebugInfo(MethodIL methodIL)
 {
     return(_debugInformationProvider.GetDebugInfo(methodIL));
 }
コード例 #21
0
        private MetadataLoadedInfo LoadMetadata()
        {
            HashSet <ModuleDesc> metadataModules          = new HashSet <ModuleDesc>();
            MetadataType         typeWithMetadataMappings = (MetadataType)_metadataDescribingModule.GetTypeByCustomAttributeTypeName(MetadataMappingTypeName);

            MethodDesc fullMetadataMethod = typeWithMetadataMappings.GetMethod("Metadata", null);
            MethodDesc weakMetadataMethod = typeWithMetadataMappings.GetMethod("WeakMetadata", null);

            ILProvider ilProvider = new ILProvider(null);

            MetadataLoadedInfo result = new MetadataLoadedInfo();

            if (fullMetadataMethod != null)
            {
                MethodIL fullMethodIL = ilProvider.GetMethodIL(fullMetadataMethod);
                ReadMetadataMethod(fullMethodIL, ref result.AllTypeMappings, ref result.MethodMappings, ref result.FieldMappings, ref metadataModules);
                foreach (var mapping in result.AllTypeMappings)
                {
                    result.TypesWithStrongMetadataMappings.Add(mapping.Key);
                }
            }

            if (weakMetadataMethod != null)
            {
                MethodIL weakMethodIL = ilProvider.GetMethodIL(weakMetadataMethod);
                Dictionary <MethodDesc, int> weakMethodMappings = new Dictionary <MethodDesc, int>();
                Dictionary <FieldDesc, int>  weakFieldMappings  = new Dictionary <FieldDesc, int>();
                ReadMetadataMethod(weakMethodIL, ref result.AllTypeMappings, ref weakMethodMappings, ref weakFieldMappings, ref metadataModules);
                if ((weakMethodMappings.Count > 0) || (weakFieldMappings.Count > 0))
                {
                    // the format does not permit weak field/method mappings
                    throw new BadImageFormatException();
                }
            }

            result.MetadataModules = ImmutableArray.CreateRange(metadataModules);

            ImmutableArray <ModuleDesc> .Builder externalMetadataModulesBuilder = ImmutableArray.CreateBuilder <ModuleDesc>();
            ImmutableArray <ModuleDesc> .Builder localMetadataModulesBuilder    = ImmutableArray.CreateBuilder <ModuleDesc>();
            foreach (ModuleDesc module in result.MetadataModules)
            {
                if (!_compilationModules.Contains(module))
                {
                    externalMetadataModulesBuilder.Add(module);
                }
                else
                {
                    localMetadataModulesBuilder.Add(module);
                }
            }
            result.ExternalMetadataModules = externalMetadataModulesBuilder.ToImmutable();
            result.LocalMetadataModules    = localMetadataModulesBuilder.ToImmutable();

            // TODO! Replace with something more complete that capture the generic instantiations that the pre-analysis
            // indicates should have been present
            foreach (var pair in result.MethodMappings)
            {
                MethodDesc reflectableMethod = pair.Key;

                if (reflectableMethod.HasInstantiation)
                {
                    continue;
                }

                if (reflectableMethod.OwningType.HasInstantiation)
                {
                    continue;
                }

                MethodDesc typicalDynamicInvokeStub;
                if (!_dynamicInvokeStubs.Value.TryGetValue(reflectableMethod, out typicalDynamicInvokeStub))
                {
                    continue;
                }

                MethodDesc instantiatiatedDynamicInvokeStub = InstantiateDynamicInvokeMethodForMethod(typicalDynamicInvokeStub, reflectableMethod);
                result.DynamicInvokeCompiledMethods.Add(instantiatiatedDynamicInvokeStub.GetCanonMethodTarget(CanonicalFormKind.Specific));
            }

            return(result);
        }
コード例 #22
0
ファイル: ILStreamReader.cs プロジェクト: yongweisun/corert
 public ILStreamReader(MethodIL methodIL)
 {
     _methodIL      = methodIL;
     _ilBytes       = methodIL.GetILBytes();
     _currentOffset = 0;
 }
コード例 #23
0
 public ILStreamReader(MethodIL methodIL)
 {
     _methodIL = methodIL;
     _reader   = new ILReader(methodIL.GetILBytes());
 }
コード例 #24
0
ファイル: Compilation.cs プロジェクト: safern/corert
 public MethodDebugInformation GetDebugInfo(MethodIL methodIL)
 {
     // This method looks odd right now, but it's an extensibility point that lets us generate
     // fake debugging information for things that don't have physical symbols.
     return(methodIL.GetDebugInfo());
 }
コード例 #25
0
        private static void HandleCall(ref DependencyList list, NodeFactory factory, MethodIL methodIL, MethodDesc methodCalled, ref Tracker tracker, ScanModes modes)
        {
            bool scanningReflection = (modes & ScanModes.Reflection) != 0;
            bool scanningInterop    = (modes & ScanModes.Interop) != 0;

            switch (methodCalled.Name)
            {
            // Enum.GetValues(Type) needs array of that type
            case "GetValues" when scanningReflection && methodCalled.OwningType == factory.TypeSystemContext.GetWellKnownType(WellKnownType.Enum):
            {
                TypeDesc type = tracker.GetLastType();
                if (type != null && type.IsEnum && !type.IsGenericDefinition /* generic enums! */)
                {
                    // Type could be something weird like MyEnum<object, __Canon> - normalize it
                    type = type.NormalizeInstantiation();

                    list = list ?? new DependencyList();
                    list.Add(factory.ConstructedTypeSymbol(type.MakeArrayType()), "Enum.GetValues");
                }
            }
            break;

            // Type.GetType(string...) needs the type with the given name
            case "GetType" when scanningReflection && methodCalled.OwningType.IsSystemType() && methodCalled.Signature.Length > 0:
            {
                string name = tracker.GetLastString();
                if (name != null &&
                    methodIL.OwningMethod.OwningType is MetadataType mdType &&
                    ResolveType(name, mdType.Module, out TypeDesc type, out ModuleDesc referenceModule) &&
                    !factory.MetadataManager.IsReflectionBlocked(type))
                {
                    const string reason = "Type.GetType";
                    list = list ?? new DependencyList();
                    list.Add(factory.MaximallyConstructableType(type), reason);

                    // Also add module metadata in case this reference was through a type forward
                    if (factory.MetadataManager.CanGenerateMetadata(referenceModule.GetGlobalModuleType()))
                    {
                        list.Add(factory.ModuleMetadata(referenceModule), reason);
                    }

                    // Opportunistically remember the type so that it flows to Type.GetMethod if needed.
                    tracker.TrackType(type);
                }
            }
            break;

            // Type.GetMethod(string...)
            case "GetMethod" when scanningReflection && methodCalled.OwningType.IsSystemType():
            {
                string   name = tracker.GetLastString();
                TypeDesc type = tracker.GetLastType();
                if (name != null &&
                    type != null)
                {
                    HandleTypeGetMethod(ref list, factory, type, name, "Type.GetMethod");
                }
            }
            break;

            // Type.GetProperty(string...)
            case "GetProperty" when scanningReflection && methodCalled.OwningType.IsSystemType():
            {
                string   name = tracker.GetLastString();
                TypeDesc type = tracker.GetLastType();
                if (name != null &&
                    type != null)
                {
                    // Just do the easy thing and assume C# naming conventions
                    HandleTypeGetMethod(ref list, factory, type, "get_" + name, "Type.GetProperty");
                    HandleTypeGetMethod(ref list, factory, type, "set_" + name, "Type.GetProperty");
                }
            }
            break;

            case "SizeOf" when scanningInterop && IsMarshalSizeOf(methodCalled):
            {
                TypeDesc type = tracker.GetLastType();
                if (IsTypeEligibleForMarshalSizeOfTracking(type))
                {
                    list = list ?? new DependencyList();

                    list.Add(factory.StructMarshallingData((DefType)type), "Marshal.SizeOf");
                }
            }
            break;
            }
        }
コード例 #26
0
        public static void Scan(ref DependencyList list, NodeFactory factory, MethodIL methodIL, ScanModes modes)
        {
            ILReader reader = new ILReader(methodIL.GetILBytes());

            Tracker tracker = new Tracker(methodIL);

            // The algorithm here is really primitive: we scan the IL forward in a single pass, remembering
            // the last type/string/token we saw.
            //
            // We then intrinsically recognize a couple methods that consume this information.
            //
            // This has obvious problems since we don't have exact knowledge of the parameters passed
            // (something being in front of a call doesn't mean it's a parameter to the call). But since
            // this is a heuristic, it's okay. We want this to be as fast as possible.
            //
            // The main purposes of this scanner is to make following patterns work:
            //
            // * Enum.GetValues(typeof(Foo)) - this is very common and we need to make sure Foo[] is compiled.
            // * Type.GetType("Foo, Bar").GetMethod("Blah") - framework uses this to work around layering problems.
            // * typeof(Foo<>).MakeGenericType(arg).GetMethod("Blah") - used in e.g. LINQ expressions implementation
            // * typeof(Foo<>).GetProperty("Blah") - used in e.g. LINQ expressions implementation
            // * Marshal.SizeOf(typeof(Foo)) - very common and we need to make sure interop data is generated

            while (reader.HasNext)
            {
                ILOpcode opcode = reader.ReadILOpcode();
                switch (opcode)
                {
                case ILOpcode.ldstr:
                    tracker.TrackStringToken(reader.ReadILToken());
                    break;

                case ILOpcode.ldtoken:
                    int token = reader.ReadILToken();
                    if (IsTypeEqualityTest(methodIL, reader, out ILReader newReader))
                    {
                        reader = newReader;
                    }
                    else
                    {
                        tracker.TrackLdTokenToken(token);
                        TypeDesc type = methodIL.GetObject(token) as TypeDesc;
                        if (type != null && !type.IsCanonicalSubtype(CanonicalFormKind.Any))
                        {
                            list = list ?? new DependencyList();
                            list.Add(factory.MaximallyConstructableType(type), "Unknown LDTOKEN use");
                        }
                    }

                    break;

                case ILOpcode.call:
                case ILOpcode.callvirt:
                    var method = methodIL.GetObject(reader.ReadILToken()) as MethodDesc;
                    if (method != null)
                    {
                        HandleCall(ref list, factory, methodIL, method, ref tracker, modes);
                    }
                    break;

                default:
                    reader.Skip(opcode);
                    break;
                }
            }
        }
コード例 #27
0
        private bool TryGetConstantArgument(MethodIL methodIL, byte[] body, OpcodeFlags[] flags, int offset, int argIndex, out int constant)
        {
            if ((flags[offset] & OpcodeFlags.BasicBlockStart) != 0)
            {
                constant = 0;
                return(false);
            }

            for (int currentOffset = offset - 1; currentOffset >= 0; currentOffset--)
            {
                if ((flags[currentOffset] & OpcodeFlags.InstructionStart) == 0)
                {
                    continue;
                }

                ILReader reader = new ILReader(body, currentOffset);
                ILOpcode opcode = reader.ReadILOpcode();
                if (opcode == ILOpcode.call || opcode == ILOpcode.callvirt)
                {
                    MethodDesc method = (MethodDesc)methodIL.GetObject(reader.ReadILToken());
                    if (argIndex == 0)
                    {
                        BodySubstitution substitution = GetSubstitution(method);
                        if (substitution != null && substitution.Value is int &&
                            (opcode != ILOpcode.callvirt || !method.IsVirtual))
                        {
                            constant = (int)substitution.Value;
                            return(true);
                        }
                        else
                        {
                            constant = 0;
                            return(false);
                        }
                    }

                    argIndex--;

                    if (method.Signature.Length > 0 || !method.Signature.IsStatic)
                    {
                        // We don't know how to skip over the parameters
                        break;
                    }
                }
                else if (opcode == ILOpcode.ldsfld)
                {
                    FieldDesc field = (FieldDesc)methodIL.GetObject(reader.ReadILToken());
                    if (argIndex == 0)
                    {
                        object substitution = GetSubstitution(field);
                        if (substitution is int)
                        {
                            constant = (int)substitution;
                            return(true);
                        }
                        else
                        {
                            constant = 0;
                            return(false);
                        }
                    }

                    argIndex--;
                }
                else if (opcode >= ILOpcode.ldc_i4_0 && opcode <= ILOpcode.ldc_i4_8)
                {
                    if (argIndex == 0)
                    {
                        constant = opcode - ILOpcode.ldc_i4_0;
                        return(true);
                    }

                    argIndex--;
                }
                else if (opcode == ILOpcode.ldc_i4)
                {
                    if (argIndex == 0)
                    {
                        constant = (int)reader.ReadILUInt32();
                        return(true);
                    }

                    argIndex--;
                }
                else if (opcode == ILOpcode.ldc_i4_s)
                {
                    if (argIndex == 0)
                    {
                        constant = (int)(sbyte)reader.ReadILByte();
                        return(true);
                    }

                    argIndex--;
                }
                else if ((opcode == ILOpcode.ldloc || opcode == ILOpcode.ldloc_s ||
                          (opcode >= ILOpcode.ldloc_0 && opcode <= ILOpcode.ldloc_3)) &&
                         ((flags[currentOffset] & OpcodeFlags.BasicBlockStart) == 0))
                {
                    // Paired stloc/ldloc that the C# compiler generates in debug code?
                    int locIndex = opcode switch
                    {
                        ILOpcode.ldloc => reader.ReadILUInt16(),
                        ILOpcode.ldloc_s => reader.ReadILByte(),
                        _ => opcode - ILOpcode.ldloc_0,
                    };

                    for (int potentialStlocOffset = currentOffset - 1; potentialStlocOffset >= 0; potentialStlocOffset--)
                    {
                        if ((flags[potentialStlocOffset] & OpcodeFlags.InstructionStart) == 0)
                        {
                            continue;
                        }

                        ILReader nestedReader = new ILReader(body, potentialStlocOffset);
                        ILOpcode otherOpcode  = nestedReader.ReadILOpcode();
                        if ((otherOpcode == ILOpcode.stloc || otherOpcode == ILOpcode.stloc_s ||
                             (otherOpcode >= ILOpcode.stloc_0 && otherOpcode <= ILOpcode.stloc_3)) &&
                            otherOpcode switch
                        {
                            ILOpcode.stloc => nestedReader.ReadILUInt16(),
                            ILOpcode.stloc_s => nestedReader.ReadILByte(),
                            _ => otherOpcode - ILOpcode.stloc_0,
                        } == locIndex)
コード例 #28
0
        public MethodIL GetMethodILWithInlinedSubstitutions(MethodIL method)
        {
            // This attempts to find all basic blocks that are unreachable after applying the substitutions.
            //
            // On a high level, we first find all the basic blocks and instruction boundaries in the IL stream.
            // This is tracked in a sidecar `flags` array that has flags for each byte of the IL stream.
            //
            // Once we have all the basic blocks and instruction boundaries, we do a marking phase to mark
            // the reachable blocks. We use substitutions to tell us what's unreachable. We consider conditional
            // branches "interesting" and whenever we see one, we seek backwards in the IL instruction stream
            // to find the instruction that feeds it. We make sure we don't cross the basic block boundary while
            // doing that. If the conditional instruction is fed by known values (either through the substitutions
            // or because it's an IL constant), we simulate the result of the comparison and only mark
            // the taken branch. We also mark any associated EH regions.
            //
            // The "seek backwards to find what feeds the comparison" only works for a couple known instructions
            // (load constant, call). It can't e.g. skip over arguments to the call.
            //
            // Last step is a sweep - we replace the tail of all unreachable blocks with "br $-2"
            // and nop out the rest. If the basic block is smaller than 2 bytes, we don't touch it.
            // We also eliminate any EH records that correspond to the stubbed out basic block.

            Debug.Assert(method.GetMethodILDefinition() == method);

            ILExceptionRegion[] ehRegions = method.GetExceptionRegions();
            byte[]        methodBytes     = method.GetILBytes();
            OpcodeFlags[] flags           = new OpcodeFlags[methodBytes.Length];

            // Offset 0 is the first basic block
            Stack <int> offsetsToVisit = new Stack <int>();

            offsetsToVisit.Push(0);

            // Basic blocks also start around EH regions
            foreach (ILExceptionRegion ehRegion in ehRegions)
            {
                if (ehRegion.Kind == ILExceptionRegionKind.Filter)
                {
                    offsetsToVisit.Push(ehRegion.FilterOffset);
                }

                offsetsToVisit.Push(ehRegion.HandlerOffset);
            }

            // Identify basic blocks and instruction boundaries
            while (offsetsToVisit.TryPop(out int offset))
            {
                // If this was already visited, we're done
                if (flags[offset] != 0)
                {
                    // Also mark as basic block start in case this was a target of a backwards branch.
                    flags[offset] |= OpcodeFlags.BasicBlockStart;
                    continue;
                }

                flags[offset] |= OpcodeFlags.BasicBlockStart;

                // Read until we reach the end of the basic block
                ILReader reader = new ILReader(methodBytes, offset);
                while (reader.HasNext)
                {
                    offset         = reader.Offset;
                    flags[offset] |= OpcodeFlags.InstructionStart;
                    ILOpcode opcode = reader.ReadILOpcode();
                    if (opcode >= ILOpcode.br_s && opcode <= ILOpcode.blt_un ||
                        opcode == ILOpcode.leave || opcode == ILOpcode.leave_s)
                    {
                        int destination = reader.ReadBranchDestination(opcode);
                        offsetsToVisit.Push(destination);

                        if (opcode != ILOpcode.leave && opcode != ILOpcode.leave_s &&
                            opcode != ILOpcode.br && opcode != ILOpcode.br_s)
                        {
                            // Branches not tested for above are conditional and the flow falls through.
                            offsetsToVisit.Push(reader.Offset);
                        }

                        flags[offset] |= OpcodeFlags.EndBasicBlock;
                    }
                    else if (opcode == ILOpcode.ret ||
                             opcode == ILOpcode.endfilter ||
                             opcode == ILOpcode.endfinally ||
                             opcode == ILOpcode.throw_ ||
                             opcode == ILOpcode.rethrow ||
                             opcode == ILOpcode.jmp)
                    {
                        // Ends basic block.
                        flags[offset] |= OpcodeFlags.EndBasicBlock;

                        reader.Skip(opcode);
                    }
                    else if (opcode == ILOpcode.switch_)
                    {
                        uint count   = reader.ReadILUInt32();
                        int  jmpBase = reader.Offset + (int)(4 * count);
                        for (uint i = 0; i < count; i++)
                        {
                            int destination = (int)reader.ReadILUInt32() + jmpBase;
                            offsetsToVisit.Push(destination);
                        }
                        // We fall through to the next basic block.
                        offsetsToVisit.Push(reader.Offset);
                        flags[offset] |= OpcodeFlags.EndBasicBlock;
                    }
                    else
                    {
                        reader.Skip(opcode);
                    }

                    if ((flags[offset] & OpcodeFlags.EndBasicBlock) != 0)
                    {
                        if (reader.HasNext)
                        {
                            // If the bytes following this basic block are not reachable from anywhere,
                            // the sweeping step would consider them to be part of the last instruction
                            // of the current basic block because of how instruction boundaries are identified.
                            // We wouldn't NOP them out if the current basic block is reachable.
                            //
                            // That's a problem for RyuJIT because RyuJIT looks at these bytes for... reasons.
                            //
                            // We can just do the same thing as RyuJIT and consider those a basic block.
                            offsetsToVisit.Push(reader.Offset);
                        }
                        break;
                    }
                }
            }

            // Mark all reachable basic blocks
            //
            // We also do another round of basic block marking to mark beginning of visible basic blocks
            // after dead branch elimination. This allows us to limit the number of potential small basic blocks
            // that are not interesting (because no code jumps to them anymore), but could prevent us from
            // finishing the process. Unreachable basic blocks smaller than 2 bytes abort the substitution
            // inlining process because we can't neutralize them (turn them into an infinite loop).
            offsetsToVisit.Push(0);
            while (offsetsToVisit.TryPop(out int offset))
            {
                // Mark as a basic block visible after constant propagation.
                flags[offset] |= OpcodeFlags.VisibleBasicBlockStart;

                // If this was already marked, we're done.
                if ((flags[offset] & OpcodeFlags.Mark) != 0)
                {
                    continue;
                }

                ILReader reader = new ILReader(methodBytes, offset);
                while (reader.HasNext)
                {
                    offset         = reader.Offset;
                    flags[offset] |= OpcodeFlags.Mark;
                    ILOpcode opcode = reader.ReadILOpcode();

                    // Mark any applicable EH blocks
                    foreach (ILExceptionRegion ehRegion in ehRegions)
                    {
                        int delta = offset - ehRegion.TryOffset;
                        if (delta >= 0 && delta < ehRegion.TryLength)
                        {
                            if (ehRegion.Kind == ILExceptionRegionKind.Filter)
                            {
                                offsetsToVisit.Push(ehRegion.FilterOffset);
                            }

                            offsetsToVisit.Push(ehRegion.HandlerOffset);

                            // RyuJIT is going to look at this basic block even though it's unreachable.
                            // Consider it visible so that we replace the tail with an endless loop.
                            int handlerEnd = ehRegion.HandlerOffset + ehRegion.HandlerLength;
                            if (handlerEnd < flags.Length)
                            {
                                flags[handlerEnd] |= OpcodeFlags.VisibleBasicBlockStart;
                            }
                        }
                    }

                    // All branches are relevant to basic block tracking
                    if (opcode == ILOpcode.brfalse || opcode == ILOpcode.brfalse_s ||
                        opcode == ILOpcode.brtrue || opcode == ILOpcode.brtrue_s)
                    {
                        int destination = reader.ReadBranchDestination(opcode);
                        if (!TryGetConstantArgument(method, methodBytes, flags, offset, 0, out int constant))
                        {
                            // Can't get the constant - both branches are live.
                            offsetsToVisit.Push(destination);
                            offsetsToVisit.Push(reader.Offset);
                        }
                        else if ((constant == 0 && (opcode == ILOpcode.brfalse || opcode == ILOpcode.brfalse_s)) ||
                                 (constant != 0 && (opcode == ILOpcode.brtrue || opcode == ILOpcode.brtrue_s)))
                        {
                            // Only the "branch taken" is live.
                            // The fallthrough marks the beginning of a visible (but not live) basic block.
                            offsetsToVisit.Push(destination);
                            flags[reader.Offset] |= OpcodeFlags.VisibleBasicBlockStart;
                        }
                        else
                        {
                            // Only fallthrough is live.
                            // The "brach taken" marks the beginning of a visible (but not live) basic block.
                            flags[destination] |= OpcodeFlags.VisibleBasicBlockStart;
                            offsetsToVisit.Push(reader.Offset);
                        }
                    }
                    else if (opcode == ILOpcode.beq || opcode == ILOpcode.beq_s ||
                             opcode == ILOpcode.bne_un || opcode == ILOpcode.bne_un_s)
                    {
                        int destination = reader.ReadBranchDestination(opcode);
                        if (!TryGetConstantArgument(method, methodBytes, flags, offset, 0, out int left) ||
                            !TryGetConstantArgument(method, methodBytes, flags, offset, 1, out int right))
                        {
                            // Can't get the constant - both branches are live.
                            offsetsToVisit.Push(destination);
                            offsetsToVisit.Push(reader.Offset);
                        }
                        else if ((left == right && (opcode == ILOpcode.beq || opcode == ILOpcode.beq_s) ||
                                  (left != right) && (opcode == ILOpcode.bne_un || opcode == ILOpcode.bne_un_s)))
                        {
                            // Only the "branch taken" is live.
                            // The fallthrough marks the beginning of a visible (but not live) basic block.
                            offsetsToVisit.Push(destination);
                            flags[reader.Offset] |= OpcodeFlags.VisibleBasicBlockStart;
                        }
                        else
                        {
                            // Only fallthrough is live.
                            // The "brach taken" marks the beginning of a visible (but not live) basic block.
                            flags[destination] |= OpcodeFlags.VisibleBasicBlockStart;
                            offsetsToVisit.Push(reader.Offset);
                        }
                    }
                    else if (opcode >= ILOpcode.br_s && opcode <= ILOpcode.blt_un ||
                             opcode == ILOpcode.leave || opcode == ILOpcode.leave_s)
                    {
                        int destination = reader.ReadBranchDestination(opcode);
                        offsetsToVisit.Push(destination);
                        if (opcode != ILOpcode.leave && opcode != ILOpcode.leave_s &&
                            opcode != ILOpcode.br && opcode != ILOpcode.br_s)
                        {
                            // Branches not tested for above are conditional and the flow falls through.
                            offsetsToVisit.Push(reader.Offset);
                        }
                        else
                        {
                            // RyuJIT is going to look at this basic block even though it's unreachable.
                            // Consider it visible so that we replace the tail with an endless loop.
                            if (reader.HasNext)
                            {
                                flags[reader.Offset] |= OpcodeFlags.VisibleBasicBlockStart;
                            }
                        }
                    }
                    else if (opcode == ILOpcode.switch_)
                    {
                        uint count   = reader.ReadILUInt32();
                        int  jmpBase = reader.Offset + (int)(4 * count);
                        for (uint i = 0; i < count; i++)
                        {
                            int destination = (int)reader.ReadILUInt32() + jmpBase;
                            offsetsToVisit.Push(destination);
                        }
                        offsetsToVisit.Push(reader.Offset);
                    }
                    else if (opcode == ILOpcode.ret ||
                             opcode == ILOpcode.endfilter ||
                             opcode == ILOpcode.endfinally ||
                             opcode == ILOpcode.throw_ ||
                             opcode == ILOpcode.rethrow ||
                             opcode == ILOpcode.jmp)
                    {
                        reader.Skip(opcode);

                        // RyuJIT is going to look at this basic block even though it's unreachable.
                        // Consider it visible so that we replace the tail with an endless loop.
                        if (reader.HasNext)
                        {
                            flags[reader.Offset] |= OpcodeFlags.VisibleBasicBlockStart;
                        }
                    }
                    else
                    {
                        reader.Skip(opcode);
                    }

                    if ((flags[offset] & OpcodeFlags.EndBasicBlock) != 0)
                    {
                        break;
                    }
                }
            }

            // Now sweep unreachable basic blocks by replacing them with nops
            bool hasUnmarkedIntructions = false;

            foreach (var flag in flags)
            {
                if ((flag & OpcodeFlags.InstructionStart) != 0 &&
                    (flag & OpcodeFlags.Mark) == 0)
                {
                    hasUnmarkedIntructions = true;
                }
            }

            if (!hasUnmarkedIntructions)
            {
                return(method);
            }

            byte[] newBody  = (byte[])methodBytes.Clone();
            int    position = 0;

            while (position < newBody.Length)
            {
                Debug.Assert((flags[position] & OpcodeFlags.InstructionStart) != 0);
                Debug.Assert((flags[position] & OpcodeFlags.VisibleBasicBlockStart) != 0);

                bool erase = (flags[position] & OpcodeFlags.Mark) == 0;

                int basicBlockStart = position;
                do
                {
                    if (erase)
                    {
                        newBody[position] = (byte)ILOpCode.Nop;
                    }
                    position++;
                } while (position < newBody.Length && (flags[position] & OpcodeFlags.VisibleBasicBlockStart) == 0);

                // If we had to nop out this basic block, we need to neutralize it by appending
                // an infinite loop ("br $-2").
                // We append instead of prepend because RyuJIT's importer has trouble with junk unreachable bytes.
                if (erase)
                {
                    if (position - basicBlockStart < 2)
                    {
                        // We cannot neutralize the basic block, so better leave the method alone.
                        // The control would fall through to the next basic block.
                        return(method);
                    }

                    newBody[position - 2] = (byte)ILOpCode.Br_s;
                    newBody[position - 1] = unchecked ((byte)-2);
                }
            }

            // EH regions with unmarked handlers belong to unmarked basic blocks
            // Need to eliminate them because they're not usable.
            ArrayBuilder <ILExceptionRegion> newEHRegions = new ArrayBuilder <ILExceptionRegion>();

            foreach (ILExceptionRegion ehRegion in ehRegions)
            {
                if ((flags[ehRegion.HandlerOffset] & OpcodeFlags.Mark) != 0)
                {
                    newEHRegions.Add(ehRegion);
                }
            }

            // Existing debug information might not match new instruction boundaries (plus there's little point
            // in generating debug information for NOPs) - generate new debug information by filtering
            // out the sequence points associated with nopped out instructions.
            MethodDebugInformation        debugInfo         = method.GetDebugInfo();
            IEnumerable <ILSequencePoint> oldSequencePoints = debugInfo?.GetSequencePoints();

            if (oldSequencePoints != null)
            {
                ArrayBuilder <ILSequencePoint> sequencePoints = new ArrayBuilder <ILSequencePoint>();
                foreach (var sequencePoint in oldSequencePoints)
                {
                    if (sequencePoint.Offset < flags.Length && (flags[sequencePoint.Offset] & OpcodeFlags.Mark) != 0)
                    {
                        sequencePoints.Add(sequencePoint);
                    }
                }

                debugInfo = new SubstitutedDebugInformation(debugInfo, sequencePoints.ToArray());
            }

            return(new SubstitutedMethodIL(method, newBody, newEHRegions.ToArray(), debugInfo));
        }
コード例 #29
0
        private MetadataLoadedInfo LoadMetadata()
        {
            HashSet <ModuleDesc> metadataModules          = new HashSet <ModuleDesc>();
            MetadataType         typeWithMetadataMappings = (MetadataType)_metadataDescribingModule.GetTypeByCustomAttributeTypeName(MetadataMappingTypeName);

            MethodDesc fullMetadataMethod           = typeWithMetadataMappings.GetMethod("Metadata", null);
            MethodDesc weakMetadataMethod           = typeWithMetadataMappings.GetMethod("WeakMetadata", null);
            MethodDesc requiredGenericTypesMethod   = typeWithMetadataMappings.GetMethod("RequiredGenericTypes", null);
            MethodDesc requiredGenericMethodsMethod = typeWithMetadataMappings.GetMethod("RequiredGenericMethods", null);
            MethodDesc requiredGenericFieldsMethod  = typeWithMetadataMappings.GetMethod("RequiredGenericFields", null);
            MethodDesc requiredTemplatesMethod      = typeWithMetadataMappings.GetMethod("CompilerDeterminedInstantiations", null);

            ILProvider ilProvider = new ILProvider(null);

            MetadataLoadedInfo result = new MetadataLoadedInfo();

            if (fullMetadataMethod != null)
            {
                MethodIL fullMethodIL = ilProvider.GetMethodIL(fullMetadataMethod);
                ReadMetadataMethod(fullMethodIL, result.AllTypeMappings, result.MethodMappings, result.FieldMappings, metadataModules);
                foreach (var mapping in result.AllTypeMappings)
                {
                    result.TypesWithStrongMetadataMappings.Add(mapping.Key);
                }
            }

            if (weakMetadataMethod != null)
            {
                MethodIL weakMethodIL = ilProvider.GetMethodIL(weakMetadataMethod);
                Dictionary <MethodDesc, int> weakMethodMappings = new Dictionary <MethodDesc, int>();
                Dictionary <FieldDesc, int>  weakFieldMappings  = new Dictionary <FieldDesc, int>();
                ReadMetadataMethod(weakMethodIL, result.AllTypeMappings, weakMethodMappings, weakFieldMappings, metadataModules);
                if ((weakMethodMappings.Count > 0) || (weakFieldMappings.Count > 0))
                {
                    // the format does not permit weak field/method mappings
                    throw new BadImageFormatException();
                }
            }

            if (requiredGenericTypesMethod != null)
            {
                foreach (var type in ReadRequiredGenericsEntities(ilProvider.GetMethodIL(requiredGenericTypesMethod)))
                {
                    Debug.Assert(type is DefType);
                    result.RequiredGenericTypes.Add((TypeDesc)type);
                }
            }

            if (requiredGenericMethodsMethod != null)
            {
                foreach (var method in ReadRequiredGenericsEntities(ilProvider.GetMethodIL(requiredGenericMethodsMethod)))
                {
                    result.RequiredGenericMethods.Add((MethodDesc)method);
                }
            }

            if (requiredGenericFieldsMethod != null)
            {
                foreach (var field in ReadRequiredGenericsEntities(ilProvider.GetMethodIL(requiredGenericFieldsMethod)))
                {
                    result.RequiredGenericFields.Add((FieldDesc)field);
                }
            }

            if (requiredTemplatesMethod != null)
            {
                ReadRequiredTemplates(ilProvider.GetMethodIL(requiredTemplatesMethod),
                                      result.RequiredTemplateTypes,
                                      result.RequiredTemplateMethods,
                                      result.RequiredTemplateFields);
            }

            result.MetadataModules = ImmutableArray.CreateRange(metadataModules);

            ImmutableArray <ModuleDesc> .Builder externalMetadataModulesBuilder = ImmutableArray.CreateBuilder <ModuleDesc>();
            ImmutableArray <ModuleDesc> .Builder localMetadataModulesBuilder    = ImmutableArray.CreateBuilder <ModuleDesc>();
            foreach (ModuleDesc module in result.MetadataModules)
            {
                if (!_compilationModules.Contains(module))
                {
                    externalMetadataModulesBuilder.Add(module);
                }
                else
                {
                    localMetadataModulesBuilder.Add(module);
                }
            }
            result.ExternalMetadataModules = externalMetadataModulesBuilder.ToImmutable();
            result.LocalMetadataModules    = localMetadataModulesBuilder.ToImmutable();

            foreach (var pair in result.MethodMappings)
            {
                MethodDesc reflectableMethod = pair.Key;

                if (reflectableMethod.HasInstantiation)
                {
                    continue;
                }

                if (reflectableMethod.OwningType.HasInstantiation)
                {
                    continue;
                }

                MethodDesc typicalDynamicInvokeStub;
                if (!_dynamicInvokeStubs.Value.TryGetValue(reflectableMethod, out typicalDynamicInvokeStub))
                {
                    continue;
                }

                MethodDesc instantiatiatedDynamicInvokeStub = InstantiateCanonicalDynamicInvokeMethodForMethod(typicalDynamicInvokeStub, reflectableMethod);
                result.DynamicInvokeCompiledMethods.Add(instantiatiatedDynamicInvokeStub);
            }

            foreach (var reflectableMethod in result.RequiredGenericMethods)
            {
                MethodDesc typicalDynamicInvokeStub;
                if (!_dynamicInvokeStubs.Value.TryGetValue(reflectableMethod.GetTypicalMethodDefinition(), out typicalDynamicInvokeStub))
                {
                    continue;
                }

                MethodDesc instantiatiatedDynamicInvokeStub = InstantiateCanonicalDynamicInvokeMethodForMethod(typicalDynamicInvokeStub, reflectableMethod);
                result.DynamicInvokeCompiledMethods.Add(instantiatiatedDynamicInvokeStub);
            }

            return(result);
        }
コード例 #30
0
        private IEnumerable <VerificationResult> VerifyMethod(EcmaModule module, MethodIL methodIL, MethodDefinitionHandle methodHandle)
        {
            var        builder = new ArrayBuilder <VerificationResult>();
            MethodDesc method  = methodIL.OwningMethod;

            try
            {
                var importer = new ILImporter(method, methodIL);

                importer.ReportVerificationError = (args) =>
                {
                    var codeResource = _stringResourceManager.Value.GetString(args.Code.ToString(), CultureInfo.InvariantCulture);

                    builder.Add(new VerificationResult()
                    {
                        Method  = methodHandle,
                        Error   = args,
                        Message = string.IsNullOrEmpty(codeResource) ? args.Code.ToString() : codeResource
                    });
                };

                importer.Verify();
            }
            catch (VerificationException)
            {
                // a result was reported already (before aborting)
            }
            catch (BadImageFormatException)
            {
                builder.Add(new VerificationResult()
                {
                    Method  = methodHandle,
                    Message = "Unable to resolve token"
                });
            }
            catch (NotImplementedException e)
            {
                reportException(e);
            }
            catch (InvalidProgramException e)
            {
                reportException(e);
            }
            catch (PlatformNotSupportedException e)
            {
                reportException(e);
            }
            catch (VerifierException e)
            {
                reportException(e);
            }
            catch (TypeSystemException e)
            {
                reportException(e);
            }

            return(builder.ToArray());

            void reportException(Exception e)
            {
                builder.Add(new VerificationResult()
                {
                    Method  = methodHandle,
                    Message = e.Message
                });
            }
        }