/// <summary>
        /// Allocate a field of the state machine of the given type, to serve as a temporary.
        /// </summary>
        private SynthesizedFieldSymbolBase AllocTemp(TypeSymbol type)
        {
            SynthesizedFieldSymbolBase result = null;

            // See if we've allocated a temp field we can reuse.  Not particularly efficient, but
            // there should not normally be a lot of hoisted temps.
            for (int i = 0; i < availableFields.Count; i++)
            {
                SynthesizedFieldSymbolBase f = availableFields[i];
                if (f.Type == type)
                {
                    result = f;
                    availableFields.RemoveAt(i);
                    break;
                }
            }

            if ((object)result == null)
            {
                var fieldName = GeneratedNames.SpillTempName(nextTempNumber++);
                result = F.StateMachineField(type, fieldName, isPublic: true);
            }

            return(result);
        }
Example #2
0
        private void FreeHoistedField(SynthesizedFieldSymbolBase field)
        {
            ArrayBuilder <SynthesizedFieldSymbolBase> fields;

            if (!availableHoistedFields.TryGetValue(field.Type, out fields))
            {
                availableHoistedFields.Add(field.Type, fields = new ArrayBuilder <SynthesizedFieldSymbolBase>());
            }

            fields.Add(field);
        }
        /// <summary>
        /// Allocate a temp of the given type, and note that it should be freed and cleared when the
        /// given local symbol goes out of scope.
        /// </summary>
        private SynthesizedFieldSymbolBase MakeHoistedTemp(LocalSymbol local, TypeSymbol type)
        {
            Debug.Assert(local.DeclarationKind == LocalDeclarationKind.CompilerGenerated);
            SynthesizedFieldSymbolBase result = AllocTemp(type);
            ArrayBuilder <SynthesizedFieldSymbolBase> freeFields;

            if (!this.freeTempsMap.TryGetValue(local, out freeFields))
            {
                this.freeTempsMap.Add(local, freeFields = ArrayBuilder <SynthesizedFieldSymbolBase> .GetInstance());
            }
            freeFields.Add(result);
            return(result);
        }
Example #4
0
        /// <summary>
        /// Allocate a temp of the given type, and note that it should be freed and cleared when the
        /// given local symbol goes out of scope.
        /// </summary>
        private SynthesizedFieldSymbolBase MakeHoistedTemp(LocalSymbol local, TypeSymbol type)
        {
            // TODO: consider tightening this assert:
            // Debug.Assert(local.SynthesizedLocalKind.IsLongLived() && local.SynthesizedLocalKind != SynthesizedLocalKind.LambdaDisplayClass ||
            //              local.SynthesizedLocalKind == SynthesizedLocalKind.AwaitSpilledTemp);

            Debug.Assert(local.SynthesizedLocalKind != SynthesizedLocalKind.None &&
                         local.SynthesizedLocalKind != SynthesizedLocalKind.LambdaDisplayClass);

            SynthesizedFieldSymbolBase result = GetOrAllocateTempField(type);
            ArrayBuilder <SynthesizedFieldSymbolBase> freeFields;

            if (!this.freeTempsMap.TryGetValue(local, out freeFields))
            {
                this.freeTempsMap.Add(local, freeFields = ArrayBuilder <SynthesizedFieldSymbolBase> .GetInstance());
            }
            freeFields.Add(result);
            return(result);
        }
 /// <summary>
 /// Add a state machine field to the set of fields available for allocation to temps
 /// </summary>
 private void FreeTemp(SynthesizedFieldSymbolBase field)
 {
     availableFields.Add(field);
 }
        /// <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);
        }
Example #7
0
 public CapturedToFrameSymbolReplacement(SynthesizedFieldSymbolBase field)
 {
     this.field = field;
 }
Example #8
0
 public CapturedToFrameSymbolReplacement(SynthesizedFieldSymbolBase hoistedField, bool isReusable)
 {
     this.HoistedField = hoistedField;
     this.isReusable   = isReusable;
 }