Exemplo n.º 1
0
        private static string GetCapturedVariableFieldName(Symbol variable, ref int uniqueId)
        {
            if (IsThis(variable))
            {
                return(GeneratedNames.ThisProxyFieldName());
            }

            var local = variable as LocalSymbol;

            if ((object)local != null)
            {
                if (local.SynthesizedKind == SynthesizedLocalKind.LambdaDisplayClass)
                {
                    return(GeneratedNames.MakeLambdaDisplayLocalName(uniqueId++));
                }

                if (local.SynthesizedKind == SynthesizedLocalKind.ExceptionFilterAwaitHoistedExceptionLocal)
                {
                    return(GeneratedNames.MakeHoistedLocalFieldName(local.SynthesizedKind, uniqueId++));
                }

                if (local.SynthesizedKind == SynthesizedLocalKind.InstrumentationPayload)
                {
                    return(GeneratedNames.MakeSynthesizedInstrumentationPayloadLocalFieldName(uniqueId++));
                }

                if (local.SynthesizedKind == SynthesizedLocalKind.UserDefined && local.ScopeDesignatorOpt?.Kind() == SyntaxKind.SwitchSection)
                {
                    return(GeneratedNames.MakeHoistedLocalFieldName(local.SynthesizedKind, uniqueId++, local.Name));
                }
            }

            Debug.Assert(variable.Name != null);
            return(variable.Name);
        }
Exemplo n.º 2
0
        private static string GetCapturedVariableFieldName(Symbol variable, ref int uniqueId)
        {
            if (IsThis(variable))
            {
                return(GeneratedNames.ThisProxyFieldName());
            }

            var local = variable as LocalSymbol;

            if ((object)local != null)
            {
                if (local.SynthesizedKind == SynthesizedLocalKind.LambdaDisplayClass)
                {
                    return(GeneratedNames.MakeLambdaDisplayLocalName(uniqueId++));
                }

                if (local.SynthesizedKind == SynthesizedLocalKind.ExceptionFilterAwaitHoistedExceptionLocal)
                {
                    return(GeneratedNames.MakeHoistedLocalFieldName(local.SynthesizedKind, uniqueId++));
                }
            }

            Debug.Assert(variable.Name != null);
            return(variable.Name);
        }
Exemplo n.º 3
0
        private static string GetCapturedVariableFieldName(Symbol variable, ref int uniqueId)
        {
            if (IsThis(variable))
            {
                return(GeneratedNames.ThisProxyFieldName());
            }

            var local = variable as LocalSymbol;

            if ((object)local != null)
            {
                if (local.SynthesizedKind == SynthesizedLocalKind.LambdaDisplayClass)
                {
                    return(GeneratedNames.MakeLambdaDisplayLocalName(uniqueId++));
                }

                if (
                    local.SynthesizedKind
                    == SynthesizedLocalKind.ExceptionFilterAwaitHoistedExceptionLocal
                    )
                {
                    return(GeneratedNames.MakeHoistedLocalFieldName(
                               local.SynthesizedKind,
                               uniqueId++
                               ));
                }

                if (local.SynthesizedKind == SynthesizedLocalKind.InstrumentationPayload)
                {
                    return(GeneratedNames.MakeSynthesizedInstrumentationPayloadLocalFieldName(
                               uniqueId++
                               ));
                }

                if (
                    local.SynthesizedKind == SynthesizedLocalKind.UserDefined &&
                    (
                        local.ScopeDesignatorOpt?.Kind() == SyntaxKind.SwitchSection ||
                        local.ScopeDesignatorOpt?.Kind() == SyntaxKind.SwitchExpressionArm
                    )
                    )
                {
                    // The programmer can use the same identifier for pattern variables in different
                    // sections of a switch statement, but they are all hoisted into
                    // the same frame for the enclosing switch statement and must be given
                    // unique field names.
                    return(GeneratedNames.MakeHoistedLocalFieldName(
                               local.SynthesizedKind,
                               uniqueId++,
                               local.Name
                               ));
                }
            }

            Debug.Assert(variable.Name != null);
            return(variable.Name);
        }
Exemplo n.º 4
0
        private static string GetCapturedVariableFieldName(Symbol variable, ref int uniqueId)
        {
            if (IsThis(variable))
            {
                return(GeneratedNames.ThisProxyFieldName());
            }

            var local = variable as LocalSymbol;

            if ((object)local != null)
            {
                if (local.SynthesizedKind == SynthesizedLocalKind.LambdaDisplayClass)
                {
                    return(GeneratedNames.MakeLambdaDisplayLocalName(uniqueId++));
                }

                if (local.SynthesizedKind == SynthesizedLocalKind.ExceptionFilterAwaitHoistedExceptionLocal)
                {
                    return(GeneratedNames.MakeHoistedLocalFieldName(local.SynthesizedKind, uniqueId++));
                }

                if (local.SynthesizedKind == SynthesizedLocalKind.InstrumentationPayload)
                {
                    return(GeneratedNames.MakeSynthesizedInstrumentationPayloadLocalFieldName(uniqueId++));
                }

                if (local.SynthesizedKind == SynthesizedLocalKind.UserDefined && local.ScopeDesignatorOpt?.Kind() == SyntaxKind.SwitchSection)
                {
                    return(GeneratedNames.MakeHoistedLocalFieldName(local.SynthesizedKind, uniqueId++, local.Name));
                }

                //
                // @MattWindsor91 (Concept-C# 2017)
                //
                // We added a new type of synthesised variable to represent
                // concept witness dictionaries, so we must generate names for
                // them.

                if (local.SynthesizedKind == SynthesizedLocalKind.ConceptDictionary)
                {
                    return(GeneratedNames.MakeConceptDictionaryLocalFieldName(uniqueId++));
                }
            }

            Debug.Assert(variable.Name != null);
            return(variable.Name);
        }
Exemplo n.º 5
0
        internal EEMethodSymbol(
            EENamedTypeSymbol container,
            string name,
            Location location,
            MethodSymbol sourceMethod,
            ImmutableArray <LocalSymbol> sourceLocals,
            ImmutableArray <LocalSymbol> sourceLocalsForBinding,
            ImmutableDictionary <string, DisplayClassVariable> sourceDisplayClassVariables,
            GenerateMethodBody generateMethodBody)
        {
            Debug.Assert(sourceMethod.IsDefinition);
            Debug.Assert(sourceMethod.ContainingSymbol == container.SubstitutedSourceType.OriginalDefinition);
            Debug.Assert(sourceLocals.All(l => l.ContainingSymbol == sourceMethod));

            _container = container;
            _name      = name;
            _locations = ImmutableArray.Create(location);

            // What we want is to map all original type parameters to the corresponding new type parameters
            // (since the old ones have the wrong owners).  Unfortunately, we have a circular dependency:
            //   1) Each new type parameter requires the entire map in order to be able to construct its constraint list.
            //   2) The map cannot be constructed until all new type parameters exist.
            // Our solution is to pass each new type parameter a lazy reference to the type map.  We then
            // initialize the map as soon as the new type parameters are available - and before they are
            // handed out - so that there is never a period where they can require the type map and find
            // it uninitialized.

            var sourceMethodTypeParameters = sourceMethod.TypeParameters;
            var allSourceTypeParameters    = container.SourceTypeParameters.Concat(sourceMethodTypeParameters);

            var getTypeMap = new Func <TypeMap>(() => this.TypeMap);

            _typeParameters = sourceMethodTypeParameters.SelectAsArray(
                (tp, i, arg) => (TypeParameterSymbol) new EETypeParameterSymbol(this, tp, i, getTypeMap),
                (object)null);
            _allTypeParameters = container.TypeParameters.Concat(_typeParameters);
            this.TypeMap       = new TypeMap(allSourceTypeParameters, _allTypeParameters);

            EENamedTypeSymbol.VerifyTypeParameters(this, _typeParameters);

            var substitutedSourceType = container.SubstitutedSourceType;

            this.SubstitutedSourceMethod = sourceMethod.AsMember(substitutedSourceType);
            if (sourceMethod.Arity > 0)
            {
                this.SubstitutedSourceMethod = this.SubstitutedSourceMethod.Construct(_typeParameters.As <TypeSymbol>());
            }
            TypeParameterChecker.Check(this.SubstitutedSourceMethod, _allTypeParameters);

            // Create a map from original parameter to target parameter.
            var parameterBuilder = ArrayBuilder <ParameterSymbol> .GetInstance();

            var substitutedSourceThisParameter    = this.SubstitutedSourceMethod.ThisParameter;
            var substitutedSourceHasThisParameter = (object)substitutedSourceThisParameter != null;

            if (substitutedSourceHasThisParameter)
            {
                _thisParameter = MakeParameterSymbol(0, GeneratedNames.ThisProxyFieldName(), substitutedSourceThisParameter);
                Debug.Assert(_thisParameter.Type == this.SubstitutedSourceMethod.ContainingType);
                parameterBuilder.Add(_thisParameter);
            }

            var ordinalOffset = (substitutedSourceHasThisParameter ? 1 : 0);

            foreach (var substitutedSourceParameter in this.SubstitutedSourceMethod.Parameters)
            {
                var ordinal = substitutedSourceParameter.Ordinal + ordinalOffset;
                Debug.Assert(ordinal == parameterBuilder.Count);
                var parameter = MakeParameterSymbol(ordinal, substitutedSourceParameter.Name, substitutedSourceParameter);
                parameterBuilder.Add(parameter);
            }

            _parameters = parameterBuilder.ToImmutableAndFree();

            var localsBuilder = ArrayBuilder <LocalSymbol> .GetInstance();

            var localsMap = PooledDictionary <LocalSymbol, LocalSymbol> .GetInstance();

            foreach (var sourceLocal in sourceLocals)
            {
                var local = sourceLocal.ToOtherMethod(this, this.TypeMap);
                localsMap.Add(sourceLocal, local);
                localsBuilder.Add(local);
            }
            this.Locals   = localsBuilder.ToImmutableAndFree();
            localsBuilder = ArrayBuilder <LocalSymbol> .GetInstance();

            foreach (var sourceLocal in sourceLocalsForBinding)
            {
                LocalSymbol local;
                if (!localsMap.TryGetValue(sourceLocal, out local))
                {
                    local = sourceLocal.ToOtherMethod(this, this.TypeMap);
                    localsMap.Add(sourceLocal, local);
                }
                localsBuilder.Add(local);
            }
            this.LocalsForBinding = localsBuilder.ToImmutableAndFree();

            // Create a map from variable name to display class field.
            var displayClassVariables = PooledDictionary <string, DisplayClassVariable> .GetInstance();

            foreach (var pair in sourceDisplayClassVariables)
            {
                var variable = pair.Value;
                var oldDisplayClassInstance = variable.DisplayClassInstance;

                // Note: we don't call ToOtherMethod in the local case because doing so would produce
                // a new LocalSymbol that would not be ReferenceEquals to the one in this.LocalsForBinding.
                var oldDisplayClassInstanceFromLocal = oldDisplayClassInstance as DisplayClassInstanceFromLocal;
                var newDisplayClassInstance          = (oldDisplayClassInstanceFromLocal == null) ?
                                                       oldDisplayClassInstance.ToOtherMethod(this, this.TypeMap) :
                                                       new DisplayClassInstanceFromLocal((EELocalSymbol)localsMap[oldDisplayClassInstanceFromLocal.Local]);

                variable = variable.SubstituteFields(newDisplayClassInstance, this.TypeMap);
                displayClassVariables.Add(pair.Key, variable);
            }

            _displayClassVariables = displayClassVariables.ToImmutableDictionary();
            displayClassVariables.Free();
            localsMap.Free();

            _generateMethodBody = generateMethodBody;
        }
Exemplo n.º 6
0
        private void CreateNonReusableLocalProxies(
            IEnumerable <Symbol> variablesToHoist,
            out IReadOnlyDictionary <Symbol, CapturedSymbolReplacement> proxies,
            out int nextFreeHoistedLocalSlot)
        {
            var proxiesBuilder = new Dictionary <Symbol, CapturedSymbolReplacement>();

            var  typeMap             = stateMachineType.TypeMap;
            bool isDebugBuild        = F.Compilation.Options.OptimizationLevel == OptimizationLevel.Debug;
            bool mapToPreviousFields = isDebugBuild && slotAllocatorOpt != null;

            nextFreeHoistedLocalSlot = mapToPreviousFields ? slotAllocatorOpt.PreviousHoistedLocalSlotCount : 0;

            foreach (var variable in variablesToHoist)
            {
                Debug.Assert(variable.Kind == SymbolKind.Local || variable.Kind == SymbolKind.Parameter);

                if (variable.Kind == SymbolKind.Local)
                {
                    var local           = (LocalSymbol)variable;
                    var synthesizedKind = local.SynthesizedKind;

                    if (!synthesizedKind.MustSurviveStateMachineSuspension())
                    {
                        continue;
                    }

                    // no need to hoist constants
                    if (local.IsConst)
                    {
                        continue;
                    }

                    if (local.RefKind != RefKind.None)
                    {
                        // we'll create proxies for these variables later:
                        Debug.Assert(synthesizedKind == SynthesizedLocalKind.Spill);
                        continue;
                    }

                    Debug.Assert(local.RefKind == RefKind.None);
                    StateMachineFieldSymbol field = null;

                    if (ShouldPreallocateNonReusableProxy(local))
                    {
                        // variable needs to be hoisted
                        var fieldType = typeMap.SubstituteType(local.Type.TypeSymbol).TypeSymbol;

                        LocalDebugId id;
                        int          slotIndex = -1;

                        if (isDebugBuild)
                        {
                            // Calculate local debug id.
                            //
                            // EnC: When emitting the baseline (gen 0) the id is stored in a custom debug information attached to the kickoff method.
                            //      When emitting a delta the id is only used to map to the existing field in the previous generation.
                            SyntaxNode declaratorSyntax = local.GetDeclaratorSyntax();
                            int        syntaxOffset     = this.method.CalculateLocalSyntaxOffset(declaratorSyntax.SpanStart, declaratorSyntax.SyntaxTree);
                            int        ordinal          = synthesizedLocalOrdinals.AssignLocalOrdinal(synthesizedKind, syntaxOffset);
                            id = new LocalDebugId(syntaxOffset, ordinal);

                            // map local id to the previous id, if available:
                            int previousSlotIndex;
                            if (mapToPreviousFields && slotAllocatorOpt.TryGetPreviousHoistedLocalSlotIndex(
                                    declaratorSyntax,
                                    F.ModuleBuilderOpt.Translate(fieldType, declaratorSyntax, diagnostics),
                                    synthesizedKind,
                                    id,
                                    diagnostics,
                                    out previousSlotIndex))
                            {
                                slotIndex = previousSlotIndex;
                            }
                        }
                        else
                        {
                            id = LocalDebugId.None;
                        }

                        if (slotIndex == -1)
                        {
                            slotIndex = nextFreeHoistedLocalSlot++;
                        }

                        string fieldName = GeneratedNames.MakeHoistedLocalFieldName(synthesizedKind, slotIndex, local.Name);
                        field = F.StateMachineField(fieldType, fieldName, new LocalSlotDebugInfo(synthesizedKind, id), slotIndex);
                    }

                    if (field != null)
                    {
                        proxiesBuilder.Add(local, new CapturedToStateMachineFieldReplacement(field, isReusable: false));
                    }
                }
                else
                {
                    var parameter = (ParameterSymbol)variable;
                    if (parameter.IsThis)
                    {
                        var containingType = method.ContainingType;
                        var proxyField     = F.StateMachineField(containingType, GeneratedNames.ThisProxyFieldName(), isPublic: true, isThis: true);
                        proxiesBuilder.Add(parameter, new CapturedToStateMachineFieldReplacement(proxyField, isReusable: false));

                        if (PreserveInitialParameterValuesAndThreadId)
                        {
                            var initialThis = containingType.IsStructType() ?
                                              F.StateMachineField(containingType, GeneratedNames.StateMachineThisParameterProxyName(), isPublic: true, isThis: true) : proxyField;

                            initialParameters.Add(parameter, new CapturedToStateMachineFieldReplacement(initialThis, isReusable: false));
                        }
                    }
                    else
                    {
                        // The field needs to be public iff it is initialized directly from the kickoff method
                        // (i.e. not for IEnumerable which loads the values from parameter proxies).
                        var proxyField = F.StateMachineField(typeMap.SubstituteType(parameter.Type.TypeSymbol).TypeSymbol, parameter.Name, isPublic: !PreserveInitialParameterValuesAndThreadId);
                        proxiesBuilder.Add(parameter, new CapturedToStateMachineFieldReplacement(proxyField, isReusable: false));

                        if (PreserveInitialParameterValuesAndThreadId)
                        {
                            var field = F.StateMachineField(typeMap.SubstituteType(parameter.Type.TypeSymbol).TypeSymbol, GeneratedNames.StateMachineParameterProxyFieldName(parameter.Name), isPublic: true);
                            initialParameters.Add(parameter, new CapturedToStateMachineFieldReplacement(field, isReusable: false));
                        }
                    }
                }
            }

            proxies = proxiesBuilder;
        }