/// <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); }
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); }
/// <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); }
public CapturedToFrameSymbolReplacement(SynthesizedFieldSymbolBase field) { this.field = field; }
public CapturedToFrameSymbolReplacement(SynthesizedFieldSymbolBase hoistedField, bool isReusable) { this.HoistedField = hoistedField; this.isReusable = isReusable; }