Пример #1
0
        private void MakeInitialProxy(TypeMap TypeMap, MultiDictionary <Symbol, CSharpSyntaxNode> locations, LocalSymbol local)
        {
            Debug.Assert(local.RefKind == RefKind.None);
            CapturedSymbolReplacement result = new CapturedToFrameSymbolReplacement(MakeHoistedField(TypeMap, local, local.Type));

            if (local.Type.IsRestrictedType())
            {
                foreach (CSharpSyntaxNode syntax in locations[local])
                {
                    // CS4013: Instance of type '{0}' cannot be used inside an anonymous function, query expression, iterator block or async method
                    diagnostics.Add(ErrorCode.ERR_SpecialByRefInLambda, syntax.Location, local.Type);
                }
            }

            variableProxies.Add(local, result);
        }
        /// <summary>
        /// Translate a statement that declares a given set of locals.  Also allocates and frees hoisted temps as
        /// required for the translation.
        /// </summary>
        /// <param name="locals">The set of locals declared in the original version of this statement</param>
        /// <param name="wrapped">A delegate to return the translation of the body of this statement</param>
        private BoundNode PossibleIteratorScope(ImmutableArray<LocalSymbol> locals, Func<BoundStatement> wrapped)
        {
            if (locals.IsDefaultOrEmpty) return wrapped();
            var proxyFields = ArrayBuilder<SynthesizedFieldSymbolBase>.GetInstance();
            foreach (var local in locals)
            {
                if (!VariablesCaptured.Contains(local)) continue;
                CapturedSymbolReplacement proxy;
                if (proxies.TryGetValue(local, out proxy))
                {
                    // All of the user-declared variables have pre-allocated proxies
                    var field = proxy.HoistedField;
                    Debug.Assert((object)field != null);
                    Debug.Assert(local.DeclarationKind != LocalDeclarationKind.CompilerGenerated); // temps have lazily allocated proxies
                    if (local.DeclarationKind != LocalDeclarationKind.CompilerGenerated) proxyFields.Add(field);
                }
                else
                {
                    if (local.RefKind == RefKind.None)
                    {
                        SynthesizedFieldSymbolBase field = MakeHoistedTemp(local, TypeMap.SubstituteType(local.Type));
                        proxy = new CapturedToFrameSymbolReplacement(field);
                        proxies.Add(local, proxy);
                    }
                    // ref temporary variables have proxies that are allocated on demand
                    // See VisitAssignmentOperator.
                }
            }

            var translatedStatement = wrapped();

            // produce code to free (e.g. mark as available for reuse) and clear (e.g. set to null) the proxies for any temps for these locals
            var clearTemps = ArrayBuilder<BoundAssignmentOperator>.GetInstance();
            foreach (var local in locals)
            {
                ArrayBuilder<SynthesizedFieldSymbolBase> frees;
                if (freeTempsMap.TryGetValue(local, out frees))
                {
                    Debug.Assert(local.DeclarationKind == LocalDeclarationKind.CompilerGenerated); // only temps are managed this way
                    freeTempsMap.Remove(local);
                    foreach (var field in frees)
                    {
                        if (MightContainReferences(field.Type))
                        {
                            clearTemps.Add(F.AssignmentExpression(F.Field(F.This(), field), F.NullOrDefault(field.Type)));
                        }
                        FreeTemp(field);
                    }
                    frees.Free();
                }
            }

            if (clearTemps.Count != 0)
            {
                translatedStatement = F.Block(
                    translatedStatement,
                    F.Block(clearTemps.Select(e => F.ExpressionStatement(e)).AsImmutable<BoundStatement>())
                    );
            }
            clearTemps.Free();

            // wrap the node in an iterator scope for debugging
            if (proxyFields.Count != 0)
            {
                translatedStatement = new BoundIteratorScope(F.Syntax, proxyFields.ToImmutable(), translatedStatement);
            }
            proxyFields.Free();

            return translatedStatement;
        }
        /// <summary>
        /// Translate a statement that declares a given set of locals.  Also allocates and frees hoisted temps as
        /// required for the translation.
        /// </summary>
        /// <param name="locals">The set of locals declared in the original version of this statement</param>
        /// <param name="wrapped">A delegate to return the translation of the body of this statement</param>
        private BoundNode PossibleIteratorScope(ImmutableArray <LocalSymbol> locals, Func <BoundStatement> wrapped)
        {
            if (locals.IsDefaultOrEmpty)
            {
                return(wrapped());
            }
            var proxyFields = ArrayBuilder <SynthesizedFieldSymbolBase> .GetInstance();

            foreach (var local in locals)
            {
                if (!VariablesCaptured.Contains(local))
                {
                    continue;
                }
                CapturedSymbolReplacement proxy;
                if (proxies.TryGetValue(local, out proxy))
                {
                    // All of the user-declared variables have pre-allocated proxies
                    var field = proxy.HoistedField;
                    Debug.Assert((object)field != null);
                    Debug.Assert(local.DeclarationKind != LocalDeclarationKind.CompilerGenerated); // temps have lazily allocated proxies
                    if (local.DeclarationKind != LocalDeclarationKind.CompilerGenerated)
                    {
                        proxyFields.Add(field);
                    }
                }
                else
                {
                    if (local.RefKind == RefKind.None)
                    {
                        SynthesizedFieldSymbolBase field = MakeHoistedTemp(local, TypeMap.SubstituteType(local.Type));
                        proxy = new CapturedToFrameSymbolReplacement(field);
                        proxies.Add(local, proxy);
                    }
                    // ref temporary variables have proxies that are allocated on demand
                    // See VisitAssignmentOperator.
                }
            }

            var translatedStatement = wrapped();

            // produce code to free (e.g. mark as available for reuse) and clear (e.g. set to null) the proxies for any temps for these locals
            var clearTemps = ArrayBuilder <BoundAssignmentOperator> .GetInstance();

            foreach (var local in locals)
            {
                ArrayBuilder <SynthesizedFieldSymbolBase> frees;
                if (freeTempsMap.TryGetValue(local, out frees))
                {
                    Debug.Assert(local.DeclarationKind == LocalDeclarationKind.CompilerGenerated); // only temps are managed this way
                    freeTempsMap.Remove(local);
                    foreach (var field in frees)
                    {
                        if (MightContainReferences(field.Type))
                        {
                            clearTemps.Add(F.AssignmentExpression(F.Field(F.This(), field), F.NullOrDefault(field.Type)));
                        }
                        FreeTemp(field);
                    }
                    frees.Free();
                }
            }

            if (clearTemps.Count != 0)
            {
                translatedStatement = F.Block(
                    translatedStatement,
                    F.Block(clearTemps.Select(e => F.ExpressionStatement(e)).AsImmutable <BoundStatement>())
                    );
            }
            clearTemps.Free();

            // wrap the node in an iterator scope for debugging
            if (proxyFields.Count != 0)
            {
                translatedStatement = new BoundIteratorScope(F.Syntax, proxyFields.ToImmutable(), translatedStatement);
            }
            proxyFields.Free();

            return(translatedStatement);
        }
Пример #4
0
        private void MakeInitialProxy(TypeMap TypeMap, MultiDictionary<Symbol, CSharpSyntaxNode> locations, LocalSymbol local)
        {
            Debug.Assert(local.RefKind == RefKind.None);
            CapturedSymbolReplacement result = new CapturedToFrameSymbolReplacement(MakeHoistedLocalField(TypeMap, local, local.Type));

            if (local.Type.IsRestrictedType())
            {
                foreach (CSharpSyntaxNode syntax in locations[local])
                {
                    // CS4013: Instance of type '{0}' cannot be used inside an anonymous function, query expression, iterator block or async method
                    diagnostics.Add(ErrorCode.ERR_SpecialByRefInLambda, syntax.Location, local.Type);
                }
            }

            variableProxies.Add(local, result);
        }
Пример #5
0
        /// <summary>
        /// Introduce a frame around the translation of the given node.
        /// </summary>
        /// <param name="node">The node whose translation should be translated to contain a frame</param>
        /// <param name="frame">The frame for the translated node</param>
        /// <param name="F">A function that computes the translation of the node.  It receives lists of added statements and added symbols</param>
        /// <returns>The translated statement, as returned from F</returns>
        private T IntroduceFrame <T>(BoundNode node, LambdaFrame frame, Func <ArrayBuilder <BoundExpression>, ArrayBuilder <LocalSymbol>, T> F)
        {
            NamedTypeSymbol frameType    = frame.ConstructIfGeneric(StaticCast <TypeSymbol> .From(currentTypeParameters));
            LocalSymbol     framePointer = new LambdaFrameLocalSymbol(this.topLevelMethod, frameType, CompilationState);

            CSharpSyntaxNode syntax = node.Syntax;

            // assign new frame to the frame variable
            CompilationState.AddSynthesizedMethod(frame.Constructor, FlowAnalysisPass.AppendImplicitReturn(MethodCompiler.BindMethodBody(frame.Constructor, CompilationState, null), frame.Constructor));

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

            MethodSymbol constructor = frame.Constructor.AsMember(frameType);

            Debug.Assert(frameType == constructor.ContainingType);
            var newFrame = new BoundObjectCreationExpression(
                syntax: syntax,
                constructor: constructor);

            prologue.Add(new BoundAssignmentOperator(syntax,
                                                     new BoundLocal(syntax, framePointer, null, frameType),
                                                     newFrame,
                                                     frameType));

            CapturedSymbolReplacement oldInnermostFrameProxy = null;

            if ((object)innermostFramePointer != null)
            {
                proxies.TryGetValue(innermostFramePointer, out oldInnermostFrameProxy);
                if (analysis.needsParentFrame.Contains(node))
                {
                    var             capturedFrame = new LambdaCapturedVariable(frame, innermostFramePointer);
                    FieldSymbol     frameParent   = capturedFrame.AsMember(frameType);
                    BoundExpression left          = new BoundFieldAccess(syntax, new BoundLocal(syntax, framePointer, null, frameType), frameParent, null);
                    BoundExpression right         = FrameOfType(syntax, frameParent.Type as NamedTypeSymbol);
                    BoundExpression assignment    = new BoundAssignmentOperator(syntax, left, right, left.Type);

                    if (this.currentMethod.MethodKind == MethodKind.Constructor && capturedFrame.Type == this.currentMethod.ContainingType && !this.seenBaseCall)
                    {
                        // Containing method is a constructor
                        // Initialization statement for the "this" proxy must be inserted
                        // after the constructor initializer statement block
                        // This insertion will be done by the delegate F
                        Debug.Assert(thisProxyInitDeferred == null);
                        thisProxyInitDeferred = assignment;
                    }
                    else
                    {
                        prologue.Add(assignment);
                    }

                    if (CompilationState.Emitting)
                    {
                        CompilationState.ModuleBuilderOpt.AddSynthesizedDefinition(frame, capturedFrame);
                    }

                    proxies[innermostFramePointer] = new CapturedToFrameSymbolReplacement(capturedFrame);
                }
            }

            // Capture any parameters of this block.  This would typically occur
            // at the top level of a method or lambda with captured parameters.
            // TODO: speed up the following by computing it in analysis.
            foreach (var v in analysis.variablesCaptured)
            {
                BoundNode varNode;
                if (!analysis.variableBlock.TryGetValue(v, out varNode) ||
                    varNode != node ||
                    analysis.declaredInsideExpressionLambda.Contains(v))
                {
                    continue;
                }

                InitVariableProxy(syntax, v, framePointer, prologue);
            }

            Symbol oldInnermostFramePointer = innermostFramePointer;

            innermostFramePointer = framePointer;
            var addedLocals = ArrayBuilder <LocalSymbol> .GetInstance();

            addedLocals.Add(framePointer);
            framePointers.Add(frame, framePointer);

            var result = F(prologue, addedLocals);

            framePointers.Remove(frame);
            innermostFramePointer = oldInnermostFramePointer;

            if ((object)innermostFramePointer != null)
            {
                if (oldInnermostFrameProxy != null)
                {
                    proxies[innermostFramePointer] = oldInnermostFrameProxy;
                }
                else
                {
                    proxies.Remove(innermostFramePointer);
                }
            }

            return(result);
        }
        /// <summary>
        /// Translate a statement that declares a given set of locals.  Also allocates and frees hoisted temps as
        /// required for the translation.
        /// </summary>
        /// <param name="locals">The set of locals declared in the original version of this statement</param>
        /// <param name="wrapped">A delegate to return the translation of the body of this statement</param>
        private BoundStatement PossibleIteratorScope(ImmutableArray<LocalSymbol> locals, Func<BoundStatement> wrapped)
        {
            if (locals.IsDefaultOrEmpty)
            {
                return wrapped();
            }

            var hoistedUserDefinedLocals = ArrayBuilder<SynthesizedFieldSymbolBase>.GetInstance();
            foreach (var local in locals)
            {
                if (!NeedsProxy(local))
                {
                    continue;
                }

                // Ref synthesized variables have proxies that are allocated in VisitAssignmentOperator.
                if (local.RefKind != RefKind.None) 
                {
                    Debug.Assert(local.SynthesizedLocalKind == SynthesizedLocalKind.AwaitSpill);
                    continue;
                }

                Debug.Assert(local.SynthesizedLocalKind == SynthesizedLocalKind.None || 
                             local.SynthesizedLocalKind.IsLongLived());

                CapturedSymbolReplacement proxy;
                if (!proxies.TryGetValue(local, out proxy))
                {
                    proxy = new CapturedToFrameSymbolReplacement(GetOrAllocateHoistedField(TypeMap.SubstituteType(local.Type)), isReusable: true);
                    proxies.Add(local, proxy);
                }

                if (local.SynthesizedLocalKind == SynthesizedLocalKind.None)
                {
                    hoistedUserDefinedLocals.Add(((CapturedToFrameSymbolReplacement)proxy).HoistedField);
                }
            }

            var translatedStatement = wrapped();
            var variableCleanup = ArrayBuilder<BoundAssignmentOperator>.GetInstance();

            // produce cleanup code for all fields of locals defined by this block 
            // as well as all proxies allocated by VisitAssignmentOperator within this block:
            foreach (var local in locals)
            {
                CapturedSymbolReplacement proxy;
                if (!proxies.TryGetValue(local, out proxy))
                {
                    continue;
                }

                var simpleProxy = proxy as CapturedToFrameSymbolReplacement;
                if (simpleProxy != null)
                {
                    AddVariableCleanup(variableCleanup, simpleProxy.HoistedField);

                    if (proxy.IsReusable)
                    {
                        FreeHoistedField(simpleProxy.HoistedField);
                    }
                }
                else
                {
                    foreach (var field in ((CapturedToExpressionSymbolReplacement)proxy).HoistedFields)
                    {
                        AddVariableCleanup(variableCleanup, field);

                        if (proxy.IsReusable)
                        {
                            FreeHoistedField(field);
                        }
                    }
                }
            }

            if (variableCleanup.Count != 0)
            {
                translatedStatement = F.Block(
                    translatedStatement,
                    F.Block(variableCleanup.SelectAsArray((e, f) => (BoundStatement)f.ExpressionStatement(e), F)));
            }

            variableCleanup.Free();

            // wrap the node in an iterator scope for debugging
            if (hoistedUserDefinedLocals.Count != 0)
            {
                translatedStatement = F.Block(new BoundIteratorScope(F.Syntax, hoistedUserDefinedLocals.ToImmutable(), translatedStatement));
            }

            hoistedUserDefinedLocals.Free();

            return translatedStatement;
        }
Пример #7
0
        /// <summary>
        /// Translate a statement that declares a given set of locals.  Also allocates and frees hoisted temps as
        /// required for the translation.
        /// </summary>
        /// <param name="locals">The set of locals declared in the original version of this statement</param>
        /// <param name="wrapped">A delegate to return the translation of the body of this statement</param>
        private BoundStatement PossibleIteratorScope(ImmutableArray <LocalSymbol> locals, Func <BoundStatement> wrapped)
        {
            if (locals.IsDefaultOrEmpty)
            {
                return(wrapped());
            }

            var hoistedUserDefinedLocals = ArrayBuilder <SynthesizedFieldSymbolBase> .GetInstance();

            foreach (var local in locals)
            {
                if (!NeedsProxy(local))
                {
                    continue;
                }

                // Ref synthesized variables have proxies that are allocated in VisitAssignmentOperator.
                if (local.RefKind != RefKind.None)
                {
                    Debug.Assert(local.SynthesizedLocalKind == SynthesizedLocalKind.AwaitSpill);
                    continue;
                }

                Debug.Assert(local.SynthesizedLocalKind == SynthesizedLocalKind.None ||
                             local.SynthesizedLocalKind.IsLongLived());

                CapturedSymbolReplacement proxy;
                if (!proxies.TryGetValue(local, out proxy))
                {
                    proxy = new CapturedToFrameSymbolReplacement(GetOrAllocateHoistedField(TypeMap.SubstituteType(local.Type)), isReusable: true);
                    proxies.Add(local, proxy);
                }

                if (local.SynthesizedLocalKind == SynthesizedLocalKind.None)
                {
                    hoistedUserDefinedLocals.Add(((CapturedToFrameSymbolReplacement)proxy).HoistedField);
                }
            }

            var translatedStatement = wrapped();
            var variableCleanup     = ArrayBuilder <BoundAssignmentOperator> .GetInstance();

            // produce cleanup code for all fields of locals defined by this block
            // as well as all proxies allocated by VisitAssignmentOperator within this block:
            foreach (var local in locals)
            {
                CapturedSymbolReplacement proxy;
                if (!proxies.TryGetValue(local, out proxy))
                {
                    continue;
                }

                var simpleProxy = proxy as CapturedToFrameSymbolReplacement;
                if (simpleProxy != null)
                {
                    AddVariableCleanup(variableCleanup, simpleProxy.HoistedField);

                    if (proxy.IsReusable)
                    {
                        FreeHoistedField(simpleProxy.HoistedField);
                    }
                }
                else
                {
                    foreach (var field in ((CapturedToExpressionSymbolReplacement)proxy).HoistedFields)
                    {
                        AddVariableCleanup(variableCleanup, field);

                        if (proxy.IsReusable)
                        {
                            FreeHoistedField(field);
                        }
                    }
                }
            }

            if (variableCleanup.Count != 0)
            {
                translatedStatement = F.Block(
                    translatedStatement,
                    F.Block(variableCleanup.SelectAsArray((e, f) => (BoundStatement)f.ExpressionStatement(e), F)));
            }

            variableCleanup.Free();

            // wrap the node in an iterator scope for debugging
            if (hoistedUserDefinedLocals.Count != 0)
            {
                translatedStatement = F.Block(new BoundIteratorScope(F.Syntax, hoistedUserDefinedLocals.ToImmutable(), translatedStatement));
            }

            hoistedUserDefinedLocals.Free();

            return(translatedStatement);
        }