private DynamicAnalysisInjector(MethodSymbol method, BoundStatement methodBody, SyntheticBoundNodeFactory methodBodyFactory, MethodSymbol createPayload, DiagnosticBag diagnostics, DebugDocumentProvider debugDocumentProvider, Instrumenter previous)
            : base(previous)
        {
            _createPayload = createPayload;
            _method        = method;
            _methodBody    = methodBody;
            _spansBuilder  = ArrayBuilder <SourceSpan> .GetInstance();

            TypeSymbol payloadElementType = methodBodyFactory.SpecialType(SpecialType.System_Boolean);

            _payloadType            = ArrayTypeSymbol.CreateCSharpArray(methodBodyFactory.Compilation.Assembly, payloadElementType);
            _methodPayload          = methodBodyFactory.SynthesizedLocal(_payloadType, kind: SynthesizedLocalKind.InstrumentationPayload, syntax: methodBody.Syntax);
            _diagnostics            = diagnostics;
            _debugDocumentProvider  = debugDocumentProvider;
            _methodHasExplicitBlock = MethodHasExplicitBlock(method);
            _methodBodyFactory      = methodBodyFactory;

            // The first point indicates entry into the method and has the span of the method definition.
            SyntaxNode syntax = MethodDeclarationIfAvailable(methodBody.Syntax);

            if (!method.IsImplicitlyDeclared)
            {
                _methodEntryInstrumentation = AddAnalysisPoint(syntax, SkipAttributes(syntax), methodBodyFactory);
            }
        }
        public static DynamicAnalysisInjector TryCreate(MethodSymbol method, BoundStatement methodBody, SyntheticBoundNodeFactory methodBodyFactory, DiagnosticBag diagnostics, DebugDocumentProvider debugDocumentProvider, Instrumenter previous)
        {
            // Do not instrument implicitly-declared methods, except for constructors.
            // Instrument implicit constructors in order to instrument member initializers.
            if (method.IsImplicitlyDeclared && !method.IsImplicitConstructor)
            {
                return null;
            }

            // Do not instrument methods marked with or in scope of ExcludeFromCodeCoverageAttribute.
            if (IsExcludedFromCodeCoverage(method))
            {
                return null;
            }

            MethodSymbol createPayload = GetCreatePayload(methodBodyFactory.Compilation, methodBody.Syntax, diagnostics);

            // Do not instrument any methods if CreatePayload is not present.
            if ((object)createPayload == null)
            {
                return null;
            }

            // Do not instrument CreatePayload if it is part of the current compilation (which occurs only during testing).
            // CreatePayload will fail at run time with an infinite recursion if it is instrumented.
            if (method.Equals(createPayload))
            {
                return null;
            }

            return new DynamicAnalysisInjector(method, methodBody, methodBodyFactory, createPayload, diagnostics, debugDocumentProvider, previous);
        }
        public MethodBody(
            byte[] ilBits,
            ushort maxStack,
            Cci.IMethodDefinition parent,
            ImmutableArray<Cci.ILocalDefinition> locals,
            SequencePointList sequencePoints,
            DebugDocumentProvider debugDocumentProvider,
            ImmutableArray<Cci.ExceptionHandlerRegion> exceptionHandlers,
            ImmutableArray<Cci.LocalScope> localScopes,
            Cci.CustomDebugInfoKind customDebugInfoKind,
            bool hasDynamicLocalVariables,
            ImmutableArray<Cci.NamespaceScope> namespaceScopes = default(ImmutableArray<Cci.NamespaceScope>),
            string iteratorClassName = null,
            ImmutableArray<Cci.LocalScope> iteratorScopes = default(ImmutableArray<Cci.LocalScope>),
            Cci.AsyncMethodBodyDebugInfo asyncMethodDebugInfo = null)
        {
            Debug.Assert(!locals.IsDefault);
            Debug.Assert(!exceptionHandlers.IsDefault);
            Debug.Assert(!localScopes.IsDefault);

            this.ilBits = ilBits;
            this.asyncMethodDebugInfo = asyncMethodDebugInfo;
            this.maxStack = maxStack;
            this.parent = parent;
            this.locals = locals;
            this.sequencePoints = sequencePoints;
            this.debugDocumentProvider = debugDocumentProvider;
            this.exceptionHandlers = exceptionHandlers;
            this.localScopes = localScopes;
            this.customDebugInfoKind = customDebugInfoKind;
            this.hasDynamicLocalVariables = hasDynamicLocalVariables;
            this.namespaceScopes = namespaceScopes.IsDefault ? ImmutableArray<Cci.NamespaceScope>.Empty : namespaceScopes;
            this.iteratorClassName = iteratorClassName;
            this.iteratorScopes = iteratorScopes.IsDefault ? ImmutableArray<Cci.LocalScope>.Empty : iteratorScopes;
        }
Esempio n. 4
0
        public MethodBody(
            byte[] ilBits,
            ushort maxStack,
            Cci.IMethodDefinition parent,
            ImmutableArray <Cci.ILocalDefinition> locals,
            SequencePointList sequencePoints,
            DebugDocumentProvider debugDocumentProvider,
            ImmutableArray <Cci.ExceptionHandlerRegion> exceptionHandlers,
            ImmutableArray <Cci.LocalScope> localScopes,
            Cci.CustomDebugInfoKind customDebugInfoKind,
            bool hasDynamicLocalVariables,
            ImmutableArray <Cci.NamespaceScope> namespaceScopes = default(ImmutableArray <Cci.NamespaceScope>),
            string iteratorClassName = null,
            ImmutableArray <Cci.LocalScope> iteratorScopes    = default(ImmutableArray <Cci.LocalScope>),
            Cci.AsyncMethodBodyDebugInfo asyncMethodDebugInfo = null)
        {
            Debug.Assert(!locals.IsDefault);
            Debug.Assert(!exceptionHandlers.IsDefault);
            Debug.Assert(!localScopes.IsDefault);

            this.ilBits = ilBits;
            this.asyncMethodDebugInfo = asyncMethodDebugInfo;
            this.maxStack             = maxStack;
            this.parent                   = parent;
            this.locals                   = locals;
            this.sequencePoints           = sequencePoints;
            this.debugDocumentProvider    = debugDocumentProvider;
            this.exceptionHandlers        = exceptionHandlers;
            this.localScopes              = localScopes;
            this.customDebugInfoKind      = customDebugInfoKind;
            this.hasDynamicLocalVariables = hasDynamicLocalVariables;
            this.namespaceScopes          = namespaceScopes.IsDefault ? ImmutableArray <Cci.NamespaceScope> .Empty : namespaceScopes;
            this.iteratorClassName        = iteratorClassName;
            this.iteratorScopes           = iteratorScopes.IsDefault ? ImmutableArray <Cci.LocalScope> .Empty : iteratorScopes;
        }
Esempio n. 5
0
        private DynamicAnalysisInjector(
            MethodSymbol method,
            BoundStatement methodBody,
            SyntheticBoundNodeFactory methodBodyFactory,
            MethodSymbol createPayloadForMethodsSpanningSingleFile,
            MethodSymbol createPayloadForMethodsSpanningMultipleFiles,
            BindingDiagnosticBag diagnostics,
            DebugDocumentProvider debugDocumentProvider,
            Instrumenter previous
            ) : base(previous)
        {
            _createPayloadForMethodsSpanningSingleFile    = createPayloadForMethodsSpanningSingleFile;
            _createPayloadForMethodsSpanningMultipleFiles =
                createPayloadForMethodsSpanningMultipleFiles;
            _method       = method;
            _methodBody   = methodBody;
            _spansBuilder = ArrayBuilder <SourceSpan> .GetInstance();

            TypeSymbol payloadElementType = methodBodyFactory.SpecialType(
                SpecialType.System_Boolean
                );

            _payloadType = ArrayTypeSymbol.CreateCSharpArray(
                methodBodyFactory.Compilation.Assembly,
                TypeWithAnnotations.Create(payloadElementType)
                );
            _diagnostics           = diagnostics;
            _debugDocumentProvider = debugDocumentProvider;
            _methodBodyFactory     = methodBodyFactory;

            // Set the factory context to generate nodes for the current method
            var oldMethod = methodBodyFactory.CurrentFunction;

            methodBodyFactory.CurrentFunction = method;

            _methodPayload = methodBodyFactory.SynthesizedLocal(
                _payloadType,
                kind: SynthesizedLocalKind.InstrumentationPayload,
                syntax: methodBody.Syntax
                );
            // The first point indicates entry into the method and has the span of the method definition.
            SyntaxNode syntax = MethodDeclarationIfAvailable(methodBody.Syntax);

            if (
                !method.IsImplicitlyDeclared &&
                !(method is SynthesizedSimpleProgramEntryPointSymbol)
                )
            {
                _methodEntryInstrumentation = AddAnalysisPoint(
                    syntax,
                    SkipAttributes(syntax),
                    methodBodyFactory
                    );
            }

            // Restore context
            methodBodyFactory.CurrentFunction = oldMethod;
        }
Esempio n. 6
0
        /// <summary>
        /// Lower a block of code by performing local rewritings.
        /// </summary>
        public static BoundStatement Rewrite(
            CSharpCompilation compilation,
            MethodSymbol method,
            int methodOrdinal,
            NamedTypeSymbol containingType,
            BoundStatement statement,
            TypeCompilationState compilationState,
            SynthesizedSubmissionFields previousSubmissionFields,
            bool allowOmissionOfConditionalCalls,
            bool instrumentForDynamicAnalysis,
            ref ImmutableArray <SourceSpan> dynamicAnalysisSpans,
            DebugDocumentProvider debugDocumentProvider,
            DiagnosticBag diagnostics,
            out bool sawLambdas,
            out bool sawLocalFunctions,
            out bool sawAwaitInExceptionHandler,
            // @MattWindsor91 (Concept-C# 2017)
            //
            // Sending concept witnesses to hoist to method compiler.
            // TODO: need to work out better way to do this
            out SmallDictionary <TypeSymbol, LocalSymbol> conceptWitnessesToHoist)
        {
            Debug.Assert(statement != null);
            Debug.Assert(compilationState != null);

            try
            {
                var factory = new SyntheticBoundNodeFactory(method, statement.Syntax, compilationState, diagnostics);
                DynamicAnalysisInjector dynamicInstrumenter = instrumentForDynamicAnalysis ? DynamicAnalysisInjector.TryCreate(method, statement, factory, diagnostics, debugDocumentProvider, Instrumenter.NoOp) : null;

                // We don’t want IL to differ based upon whether we write the PDB to a file/stream or not.
                // Presence of sequence points in the tree affects final IL, therefore, we always generate them.
                var localRewriter = new LocalRewriter(compilation, method, methodOrdinal, statement, containingType, factory, previousSubmissionFields, allowOmissionOfConditionalCalls, diagnostics,
                                                      dynamicInstrumenter != null ? new DebugInfoInjector(dynamicInstrumenter) : DebugInfoInjector.Singleton);

                var loweredStatement = (BoundStatement)localRewriter.Visit(statement);
                sawLambdas                 = localRewriter._sawLambdas;
                sawLocalFunctions          = localRewriter._sawLocalFunctions;
                sawAwaitInExceptionHandler = localRewriter._sawAwaitInExceptionHandler;
                if (dynamicInstrumenter != null)
                {
                    dynamicAnalysisSpans = dynamicInstrumenter.DynamicAnalysisSpans;
                }

                conceptWitnessesToHoist = localRewriter._conceptWitnessesToHoist;  // @MattWindsor91 (Concept-C# 2017)

                return(loweredStatement);
            }
            catch (SyntheticBoundNodeFactory.MissingPredefinedMember ex)
            {
                diagnostics.Add(ex.Diagnostic);
                sawLambdas = sawLocalFunctions = sawAwaitInExceptionHandler = false;

                conceptWitnessesToHoist = null;  // @MattWindsor91 (Concept-C# 2017)

                return(new BoundBadStatement(statement.Syntax, ImmutableArray.Create <BoundNode>(statement), hasErrors: true));
            }
        }
Esempio n. 7
0
        /// <summary>
        /// Lower a block of code by performing local rewritings.
        /// </summary>
        public static BoundStatement Rewrite(
            CSharpCompilation compilation,
            MethodSymbol method,
            int methodOrdinal,
            NamedTypeSymbol containingType,
            BoundStatement statement,
            TypeCompilationState compilationState,
            SynthesizedSubmissionFields previousSubmissionFields,
            bool allowOmissionOfConditionalCalls,
            bool instrumentForDynamicAnalysis,
            ref ImmutableArray <SourceSpan> dynamicAnalysisSpans,
            DebugDocumentProvider debugDocumentProvider,
            BindingDiagnosticBag diagnostics,
            out bool sawLambdas,
            out bool sawLocalFunctions,
            out bool sawAwaitInExceptionHandler)
        {
            Debug.Assert(statement != null);
            Debug.Assert(compilationState != null);

            try
            {
                var factory = new SyntheticBoundNodeFactory(method, statement.Syntax, compilationState, diagnostics);
                DynamicAnalysisInjector?dynamicInstrumenter = instrumentForDynamicAnalysis ? DynamicAnalysisInjector.TryCreate(method, statement, factory, diagnostics, debugDocumentProvider, Instrumenter.NoOp) : null;

                // We don’t want IL to differ based upon whether we write the PDB to a file/stream or not.
                // Presence of sequence points in the tree affects final IL, therefore, we always generate them.
                var localRewriter = new LocalRewriter(compilation, method, methodOrdinal, statement, containingType, factory, previousSubmissionFields, allowOmissionOfConditionalCalls, diagnostics,
                                                      dynamicInstrumenter != null ? new DebugInfoInjector(dynamicInstrumenter) : DebugInfoInjector.Singleton);

                statement.CheckLocalsDefined();
                var loweredStatement = localRewriter.VisitStatement(statement);
                Debug.Assert(loweredStatement is { });
                loweredStatement.CheckLocalsDefined();
                sawLambdas                 = localRewriter._sawLambdas;
                sawLocalFunctions          = localRewriter._availableLocalFunctionOrdinal != 0;
                sawAwaitInExceptionHandler = localRewriter._sawAwaitInExceptionHandler;

                if (localRewriter._needsSpilling && !loweredStatement.HasErrors)
                {
                    // Move spill sequences to a top-level statement. This handles "lifting" await and the switch expression.
                    var spilledStatement = SpillSequenceSpiller.Rewrite(loweredStatement, method, compilationState, diagnostics);
                    spilledStatement.CheckLocalsDefined();
                    loweredStatement = spilledStatement;
                }

                if (dynamicInstrumenter != null)
                {
                    dynamicAnalysisSpans = dynamicInstrumenter.DynamicAnalysisSpans;
                }
#if DEBUG
                LocalRewritingValidator.Validate(loweredStatement);
                localRewriter.AssertNoPlaceholderReplacements();
#endif
                return(loweredStatement);
            }
Esempio n. 8
0
        public static DynamicAnalysisInjector TryCreate(
            MethodSymbol method,
            BoundStatement methodBody,
            SyntheticBoundNodeFactory methodBodyFactory,
            DiagnosticBag diagnostics,
            DebugDocumentProvider debugDocumentProvider,
            Instrumenter previous)
        {
            // Do not instrument implicitly-declared methods, except for constructors.
            // Instrument implicit constructors in order to instrument member initializers.
            if (method.IsImplicitlyDeclared && !method.IsImplicitConstructor)
            {
                return(null);
            }

            // Do not instrument methods marked with or in scope of ExcludeFromCodeCoverageAttribute.
            if (IsExcludedFromCodeCoverage(method))
            {
                return(null);
            }

            MethodSymbol createPayloadForMethodsSpanningSingleFile = GetCreatePayloadOverload(
                methodBodyFactory.Compilation,
                WellKnownMember.Microsoft_CodeAnalysis_Runtime_Instrumentation__CreatePayloadForMethodsSpanningSingleFile,
                methodBody.Syntax,
                diagnostics);

            MethodSymbol createPayloadForMethodsSpanningMultipleFiles = GetCreatePayloadOverload(
                methodBodyFactory.Compilation,
                WellKnownMember.Microsoft_CodeAnalysis_Runtime_Instrumentation__CreatePayloadForMethodsSpanningMultipleFiles,
                methodBody.Syntax,
                diagnostics);

            // Do not instrument any methods if CreatePayload is not present.
            if ((object)createPayloadForMethodsSpanningSingleFile == null || (object)createPayloadForMethodsSpanningMultipleFiles == null)
            {
                return(null);
            }

            // Do not instrument CreatePayload if it is part of the current compilation (which occurs only during testing).
            // CreatePayload will fail at run time with an infinite recursion if it is instrumented.
            if (method.Equals(createPayloadForMethodsSpanningSingleFile) || method.Equals(createPayloadForMethodsSpanningMultipleFiles))
            {
                return(null);
            }

            return(new DynamicAnalysisInjector(
                       method,
                       methodBody,
                       methodBodyFactory,
                       createPayloadForMethodsSpanningSingleFile,
                       createPayloadForMethodsSpanningMultipleFiles,
                       diagnostics,
                       debugDocumentProvider,
                       previous));
        }
Esempio n. 9
0
        private static Cci.DebugSourceDocument GetSourceDocument(DebugDocumentProvider debugDocumentProvider, SyntaxNode syntax, FileLinePositionSpan span)
        {
            string path = span.Path;

            // If the path for the syntax node is empty, try the path for the entire syntax tree.
            if (path.Length == 0)
            {
                path = syntax.SyntaxTree.FilePath;
            }

            return(debugDocumentProvider.Invoke(path, basePath: ""));
        }
Esempio n. 10
0
        public MethodBody(
            ImmutableArray <byte> ilBits,
            ushort maxStack,
            Cci.IMethodDefinition parent,
            DebugId methodId,
            ImmutableArray <Cci.ILocalDefinition> locals,
            SequencePointList sequencePoints,
            DebugDocumentProvider debugDocumentProvider,
            ImmutableArray <Cci.ExceptionHandlerRegion> exceptionHandlers,
            bool areLocalsZeroed,
            bool hasStackalloc,
            ImmutableArray <Cci.LocalScope> localScopes,
            bool hasDynamicLocalVariables,
            Cci.IImportScope importScopeOpt,
            ImmutableArray <LambdaDebugInfo> lambdaDebugInfo,
            ImmutableArray <ClosureDebugInfo> closureDebugInfo,
            string stateMachineTypeNameOpt,
            ImmutableArray <StateMachineHoistedLocalScope> stateMachineHoistedLocalScopes,
            ImmutableArray <EncHoistedLocalInfo> stateMachineHoistedLocalSlots,
            ImmutableArray <Cci.ITypeReference?> stateMachineAwaiterSlots,
            StateMachineStatesDebugInfo stateMachineStatesDebugInfo,
            StateMachineMoveNextBodyDebugInfo stateMachineMoveNextDebugInfoOpt,
            DynamicAnalysisMethodBodyData dynamicAnalysisDataOpt)
        {
            Debug.Assert(!locals.IsDefault);
            Debug.Assert(!exceptionHandlers.IsDefault);
            Debug.Assert(!localScopes.IsDefault);

            _ilBits                           = ilBits;
            _maxStack                         = maxStack;
            _parent                           = parent;
            _methodId                         = methodId;
            _locals                           = locals;
            _exceptionHandlers                = exceptionHandlers;
            _areLocalsZeroed                  = areLocalsZeroed;
            HasStackalloc                     = hasStackalloc;
            _localScopes                      = localScopes;
            _hasDynamicLocalVariables         = hasDynamicLocalVariables;
            _importScopeOpt                   = importScopeOpt;
            _lambdaDebugInfo                  = lambdaDebugInfo;
            _closureDebugInfo                 = closureDebugInfo;
            _stateMachineTypeNameOpt          = stateMachineTypeNameOpt;
            _stateMachineHoistedLocalScopes   = stateMachineHoistedLocalScopes;
            _stateMachineHoistedLocalSlots    = stateMachineHoistedLocalSlots;
            _stateMachineAwaiterSlots         = stateMachineAwaiterSlots;
            _stateMachineStatesDebugInfo      = stateMachineStatesDebugInfo;
            _stateMachineMoveNextDebugInfoOpt = stateMachineMoveNextDebugInfoOpt;
            _dynamicAnalysisDataOpt           = dynamicAnalysisDataOpt;
            _sequencePoints                   = GetSequencePoints(sequencePoints, debugDocumentProvider);
        }
Esempio n. 11
0
        private static ImmutableArray <Cci.SequencePoint> GetSequencePoints(
            SequencePointList?sequencePoints,
            DebugDocumentProvider debugDocumentProvider
            )
        {
            if (sequencePoints == null || sequencePoints.IsEmpty)
            {
                return(ImmutableArray <Cci.SequencePoint> .Empty);
            }

            var sequencePointsBuilder = ArrayBuilder <Cci.SequencePoint> .GetInstance();

            sequencePoints.GetSequencePoints(debugDocumentProvider, sequencePointsBuilder);
            return(sequencePointsBuilder.ToImmutableAndFree());
        }
Esempio n. 12
0
        public MethodBody(
            ImmutableArray<byte> ilBits,
            ushort maxStack,
            Cci.IMethodDefinition parent,
            DebugId methodId,
            ImmutableArray<Cci.ILocalDefinition> locals,
            SequencePointList sequencePoints,
            DebugDocumentProvider debugDocumentProvider,
            ImmutableArray<Cci.ExceptionHandlerRegion> exceptionHandlers,
            ImmutableArray<Cci.LocalScope> localScopes,
            bool hasDynamicLocalVariables,
            Cci.IImportScope importScopeOpt,
            ImmutableArray<LambdaDebugInfo> lambdaDebugInfo,
            ImmutableArray<ClosureDebugInfo> closureDebugInfo,
            string stateMachineTypeNameOpt,
            ImmutableArray<Cci.StateMachineHoistedLocalScope> stateMachineHoistedLocalScopes,
            ImmutableArray<EncHoistedLocalInfo> stateMachineHoistedLocalSlots,
            ImmutableArray<Cci.ITypeReference> stateMachineAwaiterSlots,
            Cci.AsyncMethodBodyDebugInfo asyncMethodDebugInfo,
            DynamicAnalysisMethodBodyData dynamicAnalysisDataOpt)
        {
            Debug.Assert(!locals.IsDefault);
            Debug.Assert(!exceptionHandlers.IsDefault);
            Debug.Assert(!localScopes.IsDefault);

            _ilBits = ilBits;
            _asyncMethodDebugInfo = asyncMethodDebugInfo;
            _maxStack = maxStack;
            _parent = parent;
            _methodId = methodId;
            _locals = locals;
            _sequencePoints = sequencePoints;
            _debugDocumentProvider = debugDocumentProvider;
            _exceptionHandlers = exceptionHandlers;
            _localScopes = localScopes;
            _hasDynamicLocalVariables = hasDynamicLocalVariables;
            _importScopeOpt = importScopeOpt;
            _lambdaDebugInfo = lambdaDebugInfo;
            _closureDebugInfo = closureDebugInfo;
            _stateMachineTypeNameOpt = stateMachineTypeNameOpt;
            _stateMachineHoistedLocalScopes = stateMachineHoistedLocalScopes;
            _stateMachineHoistedLocalSlots = stateMachineHoistedLocalSlots;
            _stateMachineAwaiterSlots = stateMachineAwaiterSlots;
            _dynamicAnalysisDataOpt = dynamicAnalysisDataOpt;
        }
Esempio n. 13
0
        public MethodBody(
            byte[] ilBits,
            ushort maxStack,
            Cci.IMethodDefinition parent,
            int methodOrdinal,
            ImmutableArray <Cci.ILocalDefinition> locals,
            SequencePointList sequencePoints,
            DebugDocumentProvider debugDocumentProvider,
            ImmutableArray <Cci.ExceptionHandlerRegion> exceptionHandlers,
            ImmutableArray <Cci.LocalScope> localScopes,
            bool hasDynamicLocalVariables,
            ImmutableArray <Cci.NamespaceScope> namespaceScopes,
            Cci.NamespaceScopeEncoding namespaceScopeEncoding,
            ImmutableArray <LambdaDebugInfo> lambdaDebugInfo,
            ImmutableArray <ClosureDebugInfo> closureDebugInfo,
            string stateMachineTypeNameOpt,
            ImmutableArray <Cci.StateMachineHoistedLocalScope> stateMachineHoistedLocalScopes,
            ImmutableArray <EncHoistedLocalInfo> stateMachineHoistedLocalSlots,
            ImmutableArray <Cci.ITypeReference> stateMachineAwaiterSlots,
            Cci.AsyncMethodBodyDebugInfo asyncMethodDebugInfo)
        {
            Debug.Assert(!locals.IsDefault);
            Debug.Assert(!exceptionHandlers.IsDefault);
            Debug.Assert(!localScopes.IsDefault);

            _ilBits = ilBits;
            _asyncMethodDebugInfo = asyncMethodDebugInfo;
            _maxStack             = maxStack;
            _parent                         = parent;
            _methodOrdinal                  = methodOrdinal;
            _locals                         = locals;
            _sequencePoints                 = sequencePoints;
            _debugDocumentProvider          = debugDocumentProvider;
            _exceptionHandlers              = exceptionHandlers;
            _localScopes                    = localScopes;
            _namespaceScopeEncoding         = namespaceScopeEncoding;
            _hasDynamicLocalVariables       = hasDynamicLocalVariables;
            _namespaceScopes                = namespaceScopes.IsDefault ? ImmutableArray <Cci.NamespaceScope> .Empty : namespaceScopes;
            _lambdaDebugInfo                = lambdaDebugInfo;
            _closureDebugInfo               = closureDebugInfo;
            _stateMachineTypeNameOpt        = stateMachineTypeNameOpt;
            _stateMachineHoistedLocalScopes = stateMachineHoistedLocalScopes;
            _stateMachineHoistedLocalSlots  = stateMachineHoistedLocalSlots;
            _stateMachineAwaiterSlots       = stateMachineAwaiterSlots;
        }
Esempio n. 14
0
        public static DynamicAnalysisInjector TryCreate(MethodSymbol method, BoundStatement methodBody, SyntheticBoundNodeFactory methodBodyFactory, DiagnosticBag diagnostics, DebugDocumentProvider debugDocumentProvider, Instrumenter previous)
        {
            // Do not instrument implicitly-declared methods.
            if (!method.IsImplicitlyDeclared)
            {
                MethodSymbol createPayload = GetCreatePayload(methodBodyFactory.Compilation, methodBody.Syntax, diagnostics);

                // Do not instrument any methods if CreatePayload is not present.
                // Do not instrument CreatePayload if it is part of the current compilation (which occurs only during testing).
                // CreatePayload will fail at run time with an infinite recursion if it Is instrumented.
                if ((object)createPayload != null && !method.Equals(createPayload))
                {
                    return new DynamicAnalysisInjector(method, methodBody, methodBodyFactory, createPayload, diagnostics, debugDocumentProvider, previous);
                }
            }

            return null;
        }
Esempio n. 15
0
        private DynamicAnalysisInjector(MethodSymbol method, BoundStatement methodBody, SyntheticBoundNodeFactory methodBodyFactory, MethodSymbol createPayload, DiagnosticBag diagnostics, DebugDocumentProvider debugDocumentProvider, Instrumenter previous)
            : base(previous)
        {
            _createPayload = createPayload;
            _method = method;
            _methodBody = methodBody;
            _spansBuilder = ArrayBuilder<SourceSpan>.GetInstance();
            TypeSymbol payloadElementType = methodBodyFactory.SpecialType(SpecialType.System_Boolean);
            _payloadType = ArrayTypeSymbol.CreateCSharpArray(methodBodyFactory.Compilation.Assembly, payloadElementType);
            _methodPayload = methodBodyFactory.SynthesizedLocal(_payloadType, kind: SynthesizedLocalKind.InstrumentationPayload, syntax: methodBody.Syntax);
            _diagnostics = diagnostics;
            _debugDocumentProvider = debugDocumentProvider;
            _methodHasExplicitBlock = MethodHasExplicitBlock(method);
            _methodBodyFactory = methodBodyFactory;

            // The first point indicates entry into the method and has the span of the method definition.
            _methodEntryInstrumentation = AddAnalysisPoint(MethodDeclarationIfAvailable(methodBody.Syntax), methodBodyFactory);
        }
Esempio n. 16
0
        // Internal for testing only.
        internal MethodBodyCompiler(CSharpCompilation compilation, PEModuleBuilder moduleBeingBuilt, bool generateDebugInfo, bool hasDeclarationErrors,
                                    DiagnosticBag diagnostics, Predicate <Symbol> filter, CancellationToken cancellationToken)
        {
            this.compilation       = compilation;
            this.moduleBeingBuilt  = moduleBeingBuilt;
            this.generateDebugInfo = generateDebugInfo;
            this.cancellationToken = cancellationToken;
            this.diagnostics       = diagnostics;
            this.optimize          = compilation.Options.Optimize;
            this.filter            = filter;

            this.hasDeclarationErrors = hasDeclarationErrors;
            SetGlobalErrorIfTrue(hasDeclarationErrors);

            if (generateDebugInfo)
            {
                this.debugDocumentProvider = (path, basePath) => moduleBeingBuilt.GetOrAddDebugDocument(path, basePath, CreateDebugDocumentForFile);
                this.namespaceScopeBuilder = new NamespaceScopeBuilder(compilation);
            }
        }
Esempio n. 17
0
        // Find the document for the first non-hidden sequence point (issue #4370)
        // Returns null if a real sequence point was found.
        private FileLinePositionSpan?FindFirstRealSequencePoint(DebugDocumentProvider documentProvider)
        {
            SequencePointList current = this;

            while (current != null)
            {
                foreach (var offsetAndSpan in current._points)
                {
                    TextSpan span     = offsetAndSpan.Span;
                    bool     isHidden = span == RawSequencePoint.HiddenSequencePointSpan;
                    if (!isHidden)
                    {
                        FileLinePositionSpan fileLinePositionSpan = this._tree.GetMappedLineSpanAndVisibility(span, out isHidden);
                        if (!isHidden)
                        {
                            return(fileLinePositionSpan);
                        }
                    }
                }
                current = current._next;
            }

            return(null);
        }
Esempio n. 18
0
 private static Cci.DebugSourceDocument GetSourceDocument(DebugDocumentProvider debugDocumentProvider, SyntaxNode syntax)
 {
     return(GetSourceDocument(debugDocumentProvider, syntax, syntax.GetLocation().GetMappedLineSpan()));
 }
Esempio n. 19
0
        private static BoundExpressionStatement GetCreatePayloadStatement(
            ImmutableArray <SourceSpan> dynamicAnalysisSpans,
            SyntaxNode methodBodySyntax,
            LocalSymbol methodPayload,
            MethodSymbol createPayloadForMethodsSpanningSingleFile,
            MethodSymbol createPayloadForMethodsSpanningMultipleFiles,
            BoundExpression mvid,
            BoundExpression methodToken,
            BoundExpression payloadSlot,
            SyntheticBoundNodeFactory methodBodyFactory,
            DebugDocumentProvider debugDocumentProvider)
        {
            MethodSymbol    createPayloadOverload;
            BoundExpression fileIndexOrIndicesArgument;

            if (dynamicAnalysisSpans.IsEmpty)
            {
                createPayloadOverload = createPayloadForMethodsSpanningSingleFile;

                // For a compiler generated method that has no 'real' spans, we emit the index for
                // the document corresponding to the syntax node that is associated with its bound node.
                var document = GetSourceDocument(debugDocumentProvider, methodBodySyntax);
                fileIndexOrIndicesArgument = methodBodyFactory.SourceDocumentIndex(document);
            }
            else
            {
                var documents = PooledHashSet <DebugSourceDocument> .GetInstance();

                var fileIndices = ArrayBuilder <BoundExpression> .GetInstance();

                foreach (var span in dynamicAnalysisSpans)
                {
                    var document = span.Document;
                    if (documents.Add(document))
                    {
                        fileIndices.Add(methodBodyFactory.SourceDocumentIndex(document));
                    }
                }

                documents.Free();

                // At this point, we should have at least one document since we have already
                // handled the case where method has no 'real' spans (and therefore no documents) above.
                if (fileIndices.Count == 1)
                {
                    createPayloadOverload      = createPayloadForMethodsSpanningSingleFile;
                    fileIndexOrIndicesArgument = fileIndices.Single();
                }
                else
                {
                    createPayloadOverload = createPayloadForMethodsSpanningMultipleFiles;

                    // Order of elements in fileIndices should be deterministic because these
                    // elements were added based on order of spans in dynamicAnalysisSpans above.
                    fileIndexOrIndicesArgument = methodBodyFactory.Array(
                        methodBodyFactory.SpecialType(SpecialType.System_Int32), fileIndices.ToImmutable());
                }

                fileIndices.Free();
            }

            return(methodBodyFactory.Assignment(
                       methodBodyFactory.Local(methodPayload),
                       methodBodyFactory.Call(
                           null,
                           createPayloadOverload,
                           mvid,
                           methodToken,
                           fileIndexOrIndicesArgument,
                           payloadSlot,
                           methodBodyFactory.Literal(dynamicAnalysisSpans.Length))));
        }
Esempio n. 20
0
        // Find the document for the first non-hidden sequence point (issue #4370)
        // Returns null if a real sequence point was found.
        private FileLinePositionSpan? FindFirstRealSequencePoint(DebugDocumentProvider documentProvider)
        {
            SequencePointList current = this;
            
            while (current != null)
            {
                foreach (var offsetAndSpan in current._points)
                {
                    TextSpan span = offsetAndSpan.Span;
                    bool isHidden = span == RawSequencePoint.HiddenSequencePointSpan;
                    if (!isHidden)
                    {
                        FileLinePositionSpan fileLinePositionSpan = this._tree.GetMappedLineSpanAndVisibility(span, out isHidden);
                        if (!isHidden)
                        {

                            return fileLinePositionSpan;
                        }
                    }
                }
                current = current._next;
            }

            return null;
        }
Esempio n. 21
0
        /// <summary>
        /// Get all the sequence points, possibly mapping them using #line/ExternalSource directives, and mapping
        /// file names to debug documents with the given mapping function.
        /// </summary>
        /// <param name="documentProvider">Function that maps file paths to CCI debug documents</param>
        /// <param name="builder">where sequence points should be deposited</param>
        public void GetSequencePoints(
            DebugDocumentProvider documentProvider,
            ArrayBuilder <Cci.SequencePoint> builder)
        {
            bool   lastPathIsMapped = false;
            string lastPath         = null;

            Cci.DebugSourceDocument lastDebugDocument = null;

            FileLinePositionSpan?firstReal = FindFirstRealSequencePoint();

            if (!firstReal.HasValue)
            {
                return;
            }
            lastPath          = firstReal.Value.Path;
            lastPathIsMapped  = firstReal.Value.HasMappedPath;
            lastDebugDocument = documentProvider(lastPath, basePath: lastPathIsMapped ? this._tree.FilePath : null);

            SequencePointList current = this;

            while (current != null)
            {
                SyntaxTree currentTree = current._tree;

                foreach (OffsetAndSpan offsetAndSpan in current._points)
                {
                    TextSpan span = offsetAndSpan.Span;

                    // if it's a hidden sequence point, or a sequence point with syntax that points to a position that is inside
                    // of a hidden region (can be defined with #line hidden (C#) or implicitly by #ExternalSource (VB), make it
                    // a hidden sequence point.

                    bool isHidden = span == RawSequencePoint.HiddenSequencePointSpan;
                    FileLinePositionSpan fileLinePositionSpan = default(FileLinePositionSpan);
                    if (!isHidden)
                    {
                        fileLinePositionSpan = currentTree.GetMappedLineSpanAndVisibility(span, out isHidden);
                    }

                    if (isHidden)
                    {
                        if (lastPath == null)
                        {
                            lastPath          = currentTree.FilePath;
                            lastDebugDocument = documentProvider(lastPath, basePath: null);
                        }

                        if (lastDebugDocument != null)
                        {
                            builder.Add(new Cci.SequencePoint(
                                            lastDebugDocument,
                                            offset: offsetAndSpan.Offset,
                                            startLine: HiddenSequencePointLine,
                                            startColumn: 0,
                                            endLine: HiddenSequencePointLine,
                                            endColumn: 0));
                        }
                    }
                    else
                    {
                        if (lastPath != fileLinePositionSpan.Path || lastPathIsMapped != fileLinePositionSpan.HasMappedPath)
                        {
                            lastPath          = fileLinePositionSpan.Path;
                            lastPathIsMapped  = fileLinePositionSpan.HasMappedPath;
                            lastDebugDocument = documentProvider(lastPath, basePath: lastPathIsMapped ? currentTree.FilePath : null);
                        }

                        if (lastDebugDocument != null)
                        {
                            builder.Add(new Cci.SequencePoint(
                                            lastDebugDocument,
                                            offset: offsetAndSpan.Offset,
                                            startLine: (fileLinePositionSpan.StartLinePosition.Line == -1) ? 0 : fileLinePositionSpan.StartLinePosition.Line + 1,
                                            startColumn: fileLinePositionSpan.StartLinePosition.Character + 1,
                                            endLine: (fileLinePositionSpan.EndLinePosition.Line == -1) ? 0 : fileLinePositionSpan.EndLinePosition.Line + 1,
                                            endColumn: fileLinePositionSpan.EndLinePosition.Character + 1
                                            ));
                        }
                    }
                }

                current = current._next;
            }
        }
Esempio n. 22
0
        /// <summary>
        /// Generates method body that calls another method.
        /// Used for wrapping a method call into a method, e.g. an entry point.
        /// </summary>
        internal static MethodBody GenerateMethodBody(
            PEModuleBuilder moduleBuilder,
            MethodSymbol routine,
            Action <ILBuilder> builder,
            VariableSlotAllocator variableSlotAllocatorOpt,
            DiagnosticBag diagnostics,
            bool emittingPdb)
        {
            var compilation      = moduleBuilder.Compilation;
            var localSlotManager = new LocalSlotManager(variableSlotAllocatorOpt);
            var optimizations    = compilation.Options.OptimizationLevel;

            DebugDocumentProvider debugDocumentProvider = null;

            if (emittingPdb)
            {
                debugDocumentProvider = (path, basePath) =>
                {
                    if (path.IsPharFile())
                    {
                        path = PhpFileUtilities.BuildPharStubFileName(path);
                    }

                    return(moduleBuilder.DebugDocumentsBuilder.GetOrAddDebugDocument(
                               path,
                               basePath,
                               normalizedPath => CreateDebugSourceDocument(normalizedPath, routine)));
                };
            }

            ILBuilder il = new ILBuilder(moduleBuilder, localSlotManager, optimizations.AsOptimizationLevel());

            try
            {
                StateMachineMoveNextBodyDebugInfo stateMachineMoveNextDebugInfo = null;

                builder(il);

                //
                il.Realize();

                //
                var localVariables = il.LocalSlotManager.LocalsInOrder();

                if (localVariables.Length > 0xFFFE)
                {
                    //diagnosticsForThisMethod.Add(ErrorCode.ERR_TooManyLocals, method.Locations.First());
                }

                //if (diagnosticsForThisMethod.HasAnyErrors())
                //{
                //    // we are done here. Since there were errors we should not emit anything.
                //    return null;
                //}

                //// We will only save the IL builders when running tests.
                //if (moduleBuilder.SaveTestData)
                //{
                //    moduleBuilder.SetMethodTestData(method, builder.GetSnapshot());
                //}

                // Only compiler-generated MoveNext methods have iterator scopes.  See if this is one.
                var stateMachineHoistedLocalScopes = default(ImmutableArray <StateMachineHoistedLocalScope>);
                //if (isStateMachineMoveNextMethod)
                //{
                //    stateMachineHoistedLocalScopes = builder.GetHoistedLocalScopes();
                //}

                var stateMachineHoistedLocalSlots = default(ImmutableArray <EncHoistedLocalInfo>);
                var stateMachineAwaiterSlots      = default(ImmutableArray <Cci.ITypeReference>);
                //if (optimizations == OptimizationLevel.Debug && stateMachineTypeOpt != null)
                //{
                //    Debug.Assert(method.IsAsync || method.IsIterator);
                //    GetStateMachineSlotDebugInfo(moduleBuilder, moduleBuilder.GetSynthesizedFields(stateMachineTypeOpt), variableSlotAllocatorOpt, diagnosticsForThisMethod, out stateMachineHoistedLocalSlots, out stateMachineAwaiterSlots);
                //    Debug.Assert(!diagnostics.HasAnyErrors());
                //}

                return(new MethodBody(
                           il.RealizedIL,
                           il.MaxStack,
                           (Cci.IMethodDefinition)routine.PartialDefinitionPart ?? routine,
                           variableSlotAllocatorOpt?.MethodId ?? new DebugId(0, moduleBuilder.CurrentGenerationOrdinal),
                           localVariables,
                           il.RealizedSequencePoints,
                           debugDocumentProvider,
                           il.RealizedExceptionHandlers,
                           il.GetAllScopes(),
                           il.HasDynamicLocal,
                           null,                                     // importScopeOpt,
                           ImmutableArray <LambdaDebugInfo> .Empty,  // lambdaDebugInfo,
                           ImmutableArray <ClosureDebugInfo> .Empty, // closureDebugInfo,
                           null,                                     //stateMachineTypeOpt?.Name,
                           stateMachineHoistedLocalScopes,
                           stateMachineHoistedLocalSlots,
                           stateMachineAwaiterSlots,
                           stateMachineMoveNextDebugInfo,
                           null)); // dynamicAnalysisDataOpt
            }
            finally
            {
                // Basic blocks contain poolable builders for IL and sequence points. Free those back
                // to their pools.
                il.FreeBasicBlocks();

                //// Remember diagnostics.
                //diagnostics.AddRange(diagnosticsForThisMethod);
                //diagnosticsForThisMethod.Free();
            }
        }
Esempio n. 23
0
        public static DynamicAnalysisInjector TryCreate(MethodSymbol method, BoundStatement methodBody, SyntheticBoundNodeFactory methodBodyFactory, DiagnosticBag diagnostics, DebugDocumentProvider debugDocumentProvider, Instrumenter previous)
        {
            // Do not instrument implicitly-declared methods.
            if (!method.IsImplicitlyDeclared)
            {
                MethodSymbol createPayload = GetCreatePayload(methodBodyFactory.Compilation, methodBody.Syntax, diagnostics);

                // Do not instrument any methods if CreatePayload is not present.
                // Do not instrument CreatePayload if it is part of the current compilation (which occurs only during testing).
                // CreatePayload will fail at run time with an infinite recursion if it Is instrumented.
                if ((object)createPayload != null && !method.Equals(createPayload))
                {
                    return(new DynamicAnalysisInjector(method, methodBody, methodBodyFactory, createPayload, diagnostics, debugDocumentProvider, previous));
                }
            }

            return(null);
        }
Esempio n. 24
0
        /// <summary>
        /// Get all the sequence points, possibly mapping them using #line/ExternalSource directives, and mapping
        /// file names to debug documents with the given mapping function.
        /// </summary>
        /// <param name="documentProvider">Function that maps file paths to CCI debug documents</param>
        /// <param name="builder">where sequence points should be deposited</param>
        public void GetSequencePoints(
            DebugDocumentProvider documentProvider,
            ArrayBuilder <Cci.SequencePoint> builder)
        {
            bool   lastPathIsMapped = false;
            string lastPath         = null;

            Cci.DebugSourceDocument lastDebugDocument = null;

            FileLinePositionSpan?firstReal = FindFirstRealSequencePoint();

            if (!firstReal.HasValue)
            {
                return;
            }
            lastPath          = firstReal.Value.Path;
            lastPathIsMapped  = firstReal.Value.HasMappedPath;
            lastDebugDocument = documentProvider(lastPath, basePath: lastPathIsMapped ? this._tree.FilePath : null);

            SequencePointList current = this;

            while (current != null)
            {
                SyntaxTree currentTree = current._tree;

                foreach (var offsetAndSpan in current._points)
                {
                    TextSpan span = offsetAndSpan.Span;

                    // if it's a hidden sequence point, or a sequence point with syntax that points to a position that is inside
                    // of a hidden region (can be defined with #line hidden (C#) or implicitly by #ExternalSource (VB), make it
                    // a hidden sequence point.

                    bool isHidden = span == RawSequencePoint.HiddenSequencePointSpan;
                    FileLinePositionSpan fileLinePositionSpan = default;
                    if (!isHidden)
                    {
                        fileLinePositionSpan = currentTree.GetMappedLineSpanAndVisibility(span, out isHidden);
                    }

                    if (isHidden)
                    {
                        if (lastPath == null)
                        {
                            lastPath          = currentTree.FilePath;
                            lastDebugDocument = documentProvider(lastPath, basePath: null);
                        }

                        if (lastDebugDocument != null)
                        {
                            builder.Add(new Cci.SequencePoint(
                                            lastDebugDocument,
                                            offset: offsetAndSpan.Offset,
                                            startLine: Cci.SequencePoint.HiddenLine,
                                            startColumn: 0,
                                            endLine: Cci.SequencePoint.HiddenLine,
                                            endColumn: 0));
                        }
                    }
                    else
                    {
                        if (lastPath != fileLinePositionSpan.Path || lastPathIsMapped != fileLinePositionSpan.HasMappedPath)
                        {
                            lastPath          = fileLinePositionSpan.Path;
                            lastPathIsMapped  = fileLinePositionSpan.HasMappedPath;
                            lastDebugDocument = documentProvider(lastPath, basePath: lastPathIsMapped ? currentTree.FilePath : null);
                        }

                        if (lastDebugDocument != null)
                        {
                            int startLine   = (fileLinePositionSpan.StartLinePosition.Line == -1) ? 0 : fileLinePositionSpan.StartLinePosition.Line + 1;
                            int endLine     = (fileLinePositionSpan.EndLinePosition.Line == -1) ? 0 : fileLinePositionSpan.EndLinePosition.Line + 1;
                            int startColumn = fileLinePositionSpan.StartLinePosition.Character + 1;
                            int endColumn   = fileLinePositionSpan.EndLinePosition.Character + 1;

                            // Trim column number if necessary.
                            // Column must be in range [0, 0xffff) and end column must be greater than start column if on the same line.
                            // The Portable PDB specifies 0x10000, but StarkPlatform.Reflection.Metadata reader has an off-by-one error.
                            // Windows PDBs allow the same range.
                            const int MaxColumn = ushort.MaxValue - 1;

                            if (startColumn > MaxColumn)
                            {
                                startColumn = (startLine == endLine) ? MaxColumn - 1 : MaxColumn;
                            }

                            if (endColumn > MaxColumn)
                            {
                                endColumn = MaxColumn;
                            }

                            builder.Add(new Cci.SequencePoint(
                                            lastDebugDocument,
                                            offset: offsetAndSpan.Offset,
                                            startLine: startLine,
                                            startColumn: (ushort)startColumn,
                                            endLine: endLine,
                                            endColumn: (ushort)endColumn
                                            ));
                        }
                    }
                }

                current = current._next;
            }
        }
Esempio n. 25
0
        internal static MethodBody GenerateMethodBody(TypeCompilationState compilationState, MethodSymbol method, BoundStatement block, DiagnosticBag diagnostics,
                                                      bool optimize, DebugDocumentProvider debugDocumentProvider, ImmutableArray <NamespaceScope> namespaceScopes)
        {
            // Note: don't call diagnostics.HasAnyErrors() in release; could be expensive if compilation has many warnings.
            Debug.Assert(!diagnostics.HasAnyErrors(), "Running code generator when errors exist might be dangerous; code generator not well hardened");

            bool emitSequencePoints = !namespaceScopes.IsDefault && !method.IsAsync;
            var  module             = compilationState.ModuleBuilder;
            var  compilation        = module.Compilation;
            var  localSlotManager   = module.CreateLocalSlotManager(method);

            ILBuilder     builder = new ILBuilder(module, localSlotManager, optimize);
            DiagnosticBag diagnosticsForThisMethod = DiagnosticBag.GetInstance();

            try
            {
                AsyncMethodBodyDebugInfo asyncDebugInfo = null;
                if ((object)method.AsyncKickoffMethod == null) // is this the MoveNext of an async method?
                {
                    CodeGen.CodeGenerator.Run(
                        method, block, builder, module, diagnosticsForThisMethod, optimize, emitSequencePoints);
                }
                else
                {
                    int asyncCatchHandlerOffset;
                    ImmutableArray <int> asyncYieldPoints;
                    ImmutableArray <int> asyncResumePoints;
                    CodeGen.CodeGenerator.Run(
                        method, block, builder, module, diagnosticsForThisMethod, optimize, emitSequencePoints,
                        out asyncCatchHandlerOffset, out asyncYieldPoints, out asyncResumePoints);
                    asyncDebugInfo = new AsyncMethodBodyDebugInfo(method.AsyncKickoffMethod, asyncCatchHandlerOffset, asyncYieldPoints, asyncResumePoints);
                }

                var localVariables = builder.LocalSlotManager.LocalsInOrder();

                if (localVariables.Length > 0xFFFE)
                {
                    diagnosticsForThisMethod.Add(ErrorCode.ERR_TooManyLocals, method.Locations.First());
                }

                if (diagnosticsForThisMethod.HasAnyErrors())
                {
                    // we are done here. Since there were errors we should not emit anything.
                    return(null);
                }

                // We will only save the IL builders when running tests.
                if (module.SaveTestData)
                {
                    module.SetMethodTestData(method, builder.GetSnapshot());
                }

                // Only compiler-generated MoveNext methods have iterator scopes.  See if this is one.
                bool hasIteratorScopes =
                    method.Locations.IsEmpty && method.Name == "MoveNext" &&
                    (method.ExplicitInterfaceImplementations.Contains(compilation.GetSpecialTypeMember(SpecialMember.System_Collections_IEnumerator__MoveNext) as MethodSymbol) ||
                     method.ExplicitInterfaceImplementations.Contains(compilation.GetWellKnownTypeMember(WellKnownMember.System_Runtime_CompilerServices_IAsyncStateMachine_MoveNext) as MethodSymbol));

                var iteratorScopes = hasIteratorScopes ? builder.GetIteratorScopes() : ImmutableArray <LocalScope> .Empty;

                var iteratorOrAsyncImplementation = compilationState.GetIteratorOrAsyncImplementationClass(method);
                return(new MethodBody(
                           builder.RealizedIL,
                           builder.MaxStack,
                           method,
                           localVariables,
                           builder.RealizedSequencePoints,
                           debugDocumentProvider,
                           builder.RealizedExceptionHandlers,
                           builder.GetAllScopes(),
                           Microsoft.Cci.CustomDebugInfoKind.CSharpStyle,
                           builder.HasDynamicLocal,
                           namespaceScopes,
                           (object)iteratorOrAsyncImplementation == null ? null : iteratorOrAsyncImplementation.MetadataName,
                           iteratorScopes,
                           asyncMethodDebugInfo: asyncDebugInfo
                           ));
            }
            finally
            {
                // Basic blocks contain poolable builders for IL and sequence points. Free those back
                // to their pools.
                builder.FreeBasicBlocks();

                // Remember diagnostics.
                diagnostics.AddRange(diagnosticsForThisMethod);
                diagnosticsForThisMethod.Free();
            }
        }
Esempio n. 26
0
        internal static MethodBody GenerateMethodBody(TypeCompilationState compilationState, MethodSymbol method, BoundStatement block, DiagnosticBag diagnostics,
            bool optimize, DebugDocumentProvider debugDocumentProvider, ImmutableArray<NamespaceScope> namespaceScopes)
        {
            // Note: don't call diagnostics.HasAnyErrors() in release; could be expensive if compilation has many warnings.
            Debug.Assert(!diagnostics.HasAnyErrors(), "Running code generator when errors exist might be dangerous; code generator not well hardened");

            bool emitSequencePoints = !namespaceScopes.IsDefault && !method.IsAsync;
            var module = compilationState.ModuleBuilder;
            var compilation = module.Compilation;
            var localSlotManager = module.CreateLocalSlotManager(method);

            ILBuilder builder = new ILBuilder(module, localSlotManager, optimize);
            DiagnosticBag diagnosticsForThisMethod = DiagnosticBag.GetInstance();
            try
            {
                AsyncMethodBodyDebugInfo asyncDebugInfo = null;
                if ((object)method.AsyncKickoffMethod == null) // is this the MoveNext of an async method?
                {
                    CodeGen.CodeGenerator.Run(
                        method, block, builder, module, diagnosticsForThisMethod, optimize, emitSequencePoints);
                }
                else
                {
                    int asyncCatchHandlerOffset;
                    ImmutableArray<int> asyncYieldPoints;
                    ImmutableArray<int> asyncResumePoints;
                    CodeGen.CodeGenerator.Run(
                        method, block, builder, module, diagnosticsForThisMethod, optimize, emitSequencePoints,
                        out asyncCatchHandlerOffset, out asyncYieldPoints, out asyncResumePoints);
                    asyncDebugInfo = new AsyncMethodBodyDebugInfo(method.AsyncKickoffMethod, asyncCatchHandlerOffset, asyncYieldPoints, asyncResumePoints);
                }

                var localVariables = builder.LocalSlotManager.LocalsInOrder();

                if (localVariables.Length > 0xFFFE)
                {
                    diagnosticsForThisMethod.Add(ErrorCode.ERR_TooManyLocals, method.Locations.First());
                }

                if (diagnosticsForThisMethod.HasAnyErrors())
                {
                    // we are done here. Since there were errors we should not emit anything.
                    return null;
                }

                // We will only save the IL builders when running tests.
                if (module.SaveTestData)
                {
                    module.SetMethodTestData(method, builder.GetSnapshot());
                }

                // Only compiler-generated MoveNext methods have iterator scopes.  See if this is one.
                bool hasIteratorScopes =
                    method.Locations.IsEmpty && method.Name == "MoveNext" &&
                    (method.ExplicitInterfaceImplementations.Contains(compilation.GetSpecialTypeMember(SpecialMember.System_Collections_IEnumerator__MoveNext) as MethodSymbol) ||
                     method.ExplicitInterfaceImplementations.Contains(compilation.GetWellKnownTypeMember(WellKnownMember.System_Runtime_CompilerServices_IAsyncStateMachine_MoveNext) as MethodSymbol));

                var iteratorScopes = hasIteratorScopes ? builder.GetIteratorScopes() : ImmutableArray<LocalScope>.Empty;

                var iteratorOrAsyncImplementation = compilationState.GetIteratorOrAsyncImplementationClass(method);
                return new MethodBody(
                    builder.RealizedIL,
                    builder.MaxStack,
                    method,
                    localVariables,
                    builder.RealizedSequencePoints,
                    debugDocumentProvider,
                    builder.RealizedExceptionHandlers,
                    builder.GetAllScopes(),
                    Microsoft.Cci.CustomDebugInfoKind.CSharpStyle,
                    builder.HasDynamicLocal,
                    namespaceScopes,
                    (object)iteratorOrAsyncImplementation == null ? null : iteratorOrAsyncImplementation.MetadataName,
                    iteratorScopes,
                    asyncMethodDebugInfo: asyncDebugInfo
                );
            }
            finally
            {
                // Basic blocks contain poolable builders for IL and sequence points. Free those back
                // to their pools.
                builder.FreeBasicBlocks();

                // Remember diagnostics.
                diagnostics.AddRange(diagnosticsForThisMethod);
                diagnosticsForThisMethod.Free();
            }
        }
        /// <summary>
        /// Get all the sequence points, possibly mapping them using #line/ExternalSource directives, and mapping
        /// file names to debug documents with the given mapping function.
        /// </summary>
        /// <param name="documentProvider">Function that maps file paths to CCI debug documents</param>
        public ImmutableArray<Cci.SequencePoint> GetSequencePoints(DebugDocumentProvider documentProvider)
        {
            bool lastPathIsMapped = false;
            string lastPath = null;
            Cci.DebugSourceDocument lastDebugDocument = null;

            // First, count the number of sequence points.
            int count = 0;
            SequencePointList current = this;
            while (current != null)
            {
                count += current._points.Length;
                current = current._next;
            }

            ArrayBuilder<Cci.SequencePoint> result = ArrayBuilder<Cci.SequencePoint>.GetInstance(count);
            current = this;
            while (current != null)
            {
                SyntaxTree currentTree = current._tree;

                foreach (var offsetAndSpan in current._points)
                {
                    TextSpan span = offsetAndSpan.Span;

                    // if it's a hidden sequence point, or a sequence point with syntax that points to a position that is inside 
                    // of a hidden region (can be defined with #line hidden (C#) or implicitly by #ExternalSource (VB), make it 
                    // a hidden sequence point.

                    bool isHidden = span == RawSequencePoint.HiddenSequencePointSpan;
                    FileLinePositionSpan fileLinePositionSpan = default(FileLinePositionSpan);
                    if (!isHidden)
                    {
                        fileLinePositionSpan = currentTree.GetMappedLineSpanAndVisibility(span, out isHidden);
                    }

                    if (isHidden)
                    {
                        if (lastPath == null)
                        {
                            lastPath = currentTree.FilePath;
                            lastDebugDocument = documentProvider(lastPath, basePath: null);
                        }

                        if (lastDebugDocument != null)
                        {
                            result.Add(new Cci.SequencePoint(
                                lastDebugDocument,
                                offset: offsetAndSpan.Offset,
                                startLine: HiddenSequencePointLine,
                                startColumn: 0,
                                endLine: HiddenSequencePointLine,
                                endColumn: 0));
                        }
                    }
                    else
                    {
                        if (lastPath != fileLinePositionSpan.Path || lastPathIsMapped != fileLinePositionSpan.HasMappedPath)
                        {
                            lastPath = fileLinePositionSpan.Path;
                            lastPathIsMapped = fileLinePositionSpan.HasMappedPath;
                            lastDebugDocument = documentProvider(lastPath, basePath: lastPathIsMapped ? currentTree.FilePath : null);
                        }

                        if (lastDebugDocument != null)
                        {
                            result.Add(new Cci.SequencePoint(
                                lastDebugDocument,
                                offset: offsetAndSpan.Offset,
                                startLine: (fileLinePositionSpan.StartLinePosition.Line == -1) ? 0 : fileLinePositionSpan.StartLinePosition.Line + 1,
                                startColumn: fileLinePositionSpan.StartLinePosition.Character + 1,
                                endLine: (fileLinePositionSpan.EndLinePosition.Line == -1) ? 0 : fileLinePositionSpan.EndLinePosition.Line + 1,
                                endColumn: fileLinePositionSpan.EndLinePosition.Character + 1
                            ));
                        }
                    }
                }

                current = current._next;
            }

            return result.ToImmutableAndFree();
        }
Esempio n. 28
0
        /// <summary>
        /// Get all the sequence points, possibly mapping them using #line/ExternalSource directives, and mapping
        /// file names to debug documents with the given mapping function.
        /// </summary>
        /// <param name="documentProvider">Function that maps file paths to CCI debug documents</param>
        public ImmutableArray <Cci.SequencePoint> GetSequencePoints(DebugDocumentProvider documentProvider)
        {
            bool   lastPathIsMapped = false;
            string lastPath         = null;

            Cci.DebugSourceDocument lastDebugDocument = null;

            // First, count the number of sequence points.
            int count = 0;
            SequencePointList current = this;

            while (current != null)
            {
                count  += current._points.Length;
                current = current._next;
            }

            ArrayBuilder <Cci.SequencePoint> result = ArrayBuilder <Cci.SequencePoint> .GetInstance(count);

            current = this;
            while (current != null)
            {
                SyntaxTree currentTree = current._tree;

                foreach (var offsetAndSpan in current._points)
                {
                    TextSpan span = offsetAndSpan.Span;

                    // if it's a hidden sequence point, or a sequence point with syntax that points to a position that is inside
                    // of a hidden region (can be defined with #line hidden (C#) or implicitly by #ExternalSource (VB), make it
                    // a hidden sequence point.

                    bool isHidden = span == RawSequencePoint.HiddenSequencePointSpan;
                    FileLinePositionSpan fileLinePositionSpan = default(FileLinePositionSpan);
                    if (!isHidden)
                    {
                        fileLinePositionSpan = currentTree.GetMappedLineSpanAndVisibility(span, out isHidden);
                    }

                    if (isHidden)
                    {
                        if (lastPath == null)
                        {
                            lastPath          = currentTree.FilePath;
                            lastDebugDocument = documentProvider(lastPath, basePath: null);
                        }

                        if (lastDebugDocument != null)
                        {
                            result.Add(new Cci.SequencePoint(
                                           lastDebugDocument,
                                           offset: offsetAndSpan.Offset,
                                           startLine: HiddenSequencePointLine,
                                           startColumn: 0,
                                           endLine: HiddenSequencePointLine,
                                           endColumn: 0));
                        }
                    }
                    else
                    {
                        if (lastPath != fileLinePositionSpan.Path || lastPathIsMapped != fileLinePositionSpan.HasMappedPath)
                        {
                            lastPath          = fileLinePositionSpan.Path;
                            lastPathIsMapped  = fileLinePositionSpan.HasMappedPath;
                            lastDebugDocument = documentProvider(lastPath, basePath: lastPathIsMapped ? currentTree.FilePath : null);
                        }

                        if (lastDebugDocument != null)
                        {
                            result.Add(new Cci.SequencePoint(
                                           lastDebugDocument,
                                           offset: offsetAndSpan.Offset,
                                           startLine: (fileLinePositionSpan.StartLinePosition.Line == -1) ? 0 : fileLinePositionSpan.StartLinePosition.Line + 1,
                                           startColumn: fileLinePositionSpan.StartLinePosition.Character + 1,
                                           endLine: (fileLinePositionSpan.EndLinePosition.Line == -1) ? 0 : fileLinePositionSpan.EndLinePosition.Line + 1,
                                           endColumn: fileLinePositionSpan.EndLinePosition.Character + 1
                                           ));
                        }
                    }
                }

                current = current._next;
            }

            return(result.ToImmutableAndFree());
        }