Esempio n. 1
0
        private static EncLocalInfo MapLocalInfo(EncLocalInfo info, SymbolMatcher map)
        {
            Debug.Assert(!info.IsDefault);
            if (info.IsUnused)
            {
                Debug.Assert(info.Signature != null);
                return(info);
            }

            return(new EncLocalInfo(info.SlotInfo, map.MapReference(info.Type), info.Constraints, info.Signature));
        }
Esempio n. 2
0
        public override LocalDefinition GetPreviousLocal(
            Cci.ITypeReference currentType,
            ILocalSymbolInternal currentLocalSymbol,
            string nameOpt,
            SynthesizedLocalKind kind,
            LocalDebugId id,
            uint pdbAttributes,
            LocalSlotConstraints constraints,
            bool isDynamic,
            ImmutableArray <TypedConstant> dynamicTransformFlags)
        {
            if (id.IsNone)
            {
                return(null);
            }

            LocalDebugId previousId;

            if (!TryGetPreviousLocalId(currentLocalSymbol.GetDeclaratorSyntax(), id, out previousId))
            {
                return(null);
            }

            var previousType = _symbolMap.MapReference(currentType);

            if (previousType == null)
            {
                return(null);
            }

            // TODO (bug #781309): Should report a warning if the type of the local has changed
            // and the previous value will be dropped.
            var localKey = new EncLocalInfo(new LocalSlotDebugInfo(kind, previousId), previousType, constraints, signature: null);

            int slot;

            if (!_previousLocalSlots.TryGetValue(localKey, out slot))
            {
                return(null);
            }

            return(new LocalDefinition(
                       currentLocalSymbol,
                       nameOpt,
                       currentType,
                       slot,
                       kind,
                       id,
                       pdbAttributes,
                       constraints,
                       isDynamic,
                       dynamicTransformFlags));
        }
Esempio n. 3
0
        public EncVariableSlotAllocator(
            SymbolMatcher symbolMap,
            Func <SyntaxNode, SyntaxNode> syntaxMapOpt,
            IMethodSymbolInternal previousTopLevelMethod,
            DebugId methodId,
            ImmutableArray <EncLocalInfo> previousLocals,
            IReadOnlyDictionary <int, KeyValuePair <DebugId, int> > lambdaMapOpt,
            IReadOnlyDictionary <int, DebugId> closureMapOpt,
            string stateMachineTypeNameOpt,
            int hoistedLocalSlotCount,
            IReadOnlyDictionary <EncHoistedLocalInfo, int> hoistedLocalSlotsOpt,
            int awaiterCount,
            IReadOnlyDictionary <Cci.ITypeReference, int> awaiterMapOpt,
            LambdaSyntaxFacts lambdaSyntaxFacts)
        {
            Debug.Assert(symbolMap != null);
            Debug.Assert(previousTopLevelMethod != null);
            Debug.Assert(!previousLocals.IsDefault);

            _symbolMap              = symbolMap;
            _syntaxMapOpt           = syntaxMapOpt;
            _previousLocals         = previousLocals;
            _previousTopLevelMethod = previousTopLevelMethod;
            _methodId                = methodId;
            _hoistedLocalSlotsOpt    = hoistedLocalSlotsOpt;
            _hoistedLocalSlotCount   = hoistedLocalSlotCount;
            _stateMachineTypeNameOpt = stateMachineTypeNameOpt;
            _awaiterCount            = awaiterCount;
            _awaiterMapOpt           = awaiterMapOpt;
            _lambdaMapOpt            = lambdaMapOpt;
            _closureMapOpt           = closureMapOpt;
            _lambdaSyntaxFacts       = lambdaSyntaxFacts;

            // Create a map from local info to slot.
            Dictionary <EncLocalInfo, int> previousLocalInfoToSlot = new Dictionary <EncLocalInfo, int>();

            for (int slot = 0; slot < previousLocals.Length; slot++)
            {
                EncLocalInfo localInfo = previousLocals[slot];
                Debug.Assert(!localInfo.IsDefault);
                if (localInfo.IsUnused)
                {
                    // Unrecognized or deleted local.
                    continue;
                }

                previousLocalInfoToSlot.Add(localInfo, slot);
            }

            _previousLocalSlots = previousLocalInfoToSlot;
        }
        public override LocalDefinition GetPreviousLocal(
            Cci.ITypeReference type,
            ILocalSymbol symbol,
            string nameOpt,
            CommonSynthesizedLocalKind synthesizedKind,
            uint pdbAttributes,
            LocalSlotConstraints constraints,
            bool isDynamic,
            ImmutableArray <TypedConstant> dynamicTransformFlags)
        {
            var syntaxRefs = symbol.DeclaringSyntaxReferences;

            Debug.Assert(!syntaxRefs.IsDefault);

            if (!syntaxRefs.IsDefaultOrEmpty)
            {
                var currentSyntax  = syntaxRefs[0].GetSyntax();
                var previousSyntax = syntaxMap(currentSyntax);
                if (previousSyntax != null)
                {
                    int offset;
                    if (previousDeclaratorToOffset.TryGetValue(previousSyntax, out offset))
                    {
                        var previousType = symbolMap.MapReference(type);
                        if (previousType != null)
                        {
                            var localKey = new EncLocalInfo(offset, previousType, constraints, synthesizedKind, signature: null);
                            int slot;
                            // Should report a warning if the type of the local has changed
                            // and the previous value will be dropped. (Bug #781309.)
                            if (previousLocalInfoToSlot.TryGetValue(localKey, out slot))
                            {
                                return(new LocalDefinition(
                                           symbol,
                                           nameOpt,
                                           type,
                                           slot,
                                           synthesizedKind,
                                           pdbAttributes,
                                           constraints,
                                           isDynamic,
                                           dynamicTransformFlags));
                            }
                        }
                    }
                }
            }

            return(null);
        }
Esempio n. 5
0
            private void AddLocal(TempKind tempKind)
            {
                var info = this.localInfo[this.slotIndex];

                // We do not emit custom modifiers on locals so ignore the
                // previous version of the local if it had custom modifiers.
                if (info.CustomModifiers.IsDefaultOrEmpty)
                {
                    var constraints = GetConstraints(info);
                    var local       = new Microsoft.CodeAnalysis.Emit.EncLocalInfo(this.offset, (Cci.ITypeReference)info.Type, constraints, (int)tempKind);
                    this.locals.Add(local, this.slotIndex);
                }

                this.slotIndex++;
            }
Esempio n. 6
0
        /// <summary>
        /// Match local declarations to names to generate a map from
        /// declaration to local slot. The names are indexed by slot and the
        /// assumption is that declarations are in the same order as slots.
        /// </summary>
        private static ImmutableArray <Microsoft.CodeAnalysis.Emit.EncLocalInfo> GetLocalSlots(
            MethodSymbol method,
            ImmutableArray <string> localNames,
            ImmutableArray <MetadataDecoder.LocalInfo> localInfo)
        {
            var syntaxRefs = method.DeclaringSyntaxReferences;

            // No syntax refs for synthesized methods.
            if (syntaxRefs.Length == 0)
            {
                return(ImmutableArray <Microsoft.CodeAnalysis.Emit.EncLocalInfo> .Empty);
            }

            var syntax  = syntaxRefs[0].GetSyntax();
            var map     = new Dictionary <Microsoft.CodeAnalysis.Emit.EncLocalInfo, int>();
            var visitor = new GetLocalsVisitor(localNames, localInfo, map);

            visitor.Visit(syntax);
            var locals = new Microsoft.CodeAnalysis.Emit.EncLocalInfo[localInfo.Length];

            foreach (var pair in map)
            {
                locals[pair.Value] = pair.Key;
            }

            // Populate any remaining locals that were not matched to source.
            for (int i = 0; i < locals.Length; i++)
            {
                if (locals[i].IsDefault)
                {
                    var info        = localInfo[i];
                    var constraints = GetConstraints(info);
                    locals[i] = new Microsoft.CodeAnalysis.Emit.EncLocalInfo((Cci.ITypeReference)info.Type, constraints);
                }
            }

            return(ImmutableArray.Create(locals));
        }
Esempio n. 7
0
        internal override bool TryGetPreviousLocals(
            Microsoft.CodeAnalysis.Emit.EmitBaseline baseline,
            IMethodSymbol method,
            out ImmutableArray <Microsoft.CodeAnalysis.Emit.EncLocalInfo> previousLocals,
            out GetPreviousLocalSlot getPreviousLocalSlot)
        {
            previousLocals       = default(ImmutableArray <Microsoft.CodeAnalysis.Emit.EncLocalInfo>);
            getPreviousLocalSlot = NoPreviousLocalSlot;

            MethodHandle handle;

            if (!this.TryGetMethodHandle(baseline, (Cci.IMethodDefinition)method, out handle))
            {
                // Unrecognized method. Must have been added in the current compilation.
                return(false);
            }

            MethodDefinitionEntry methodEntry;

            if (!this.methodMap.TryGetValue((MethodSymbol)method, out methodEntry))
            {
                // Not part of changeset. No need to preserve locals.
                return(false);
            }

            if (!methodEntry.PreserveLocalVariables)
            {
                // Not necessary to preserve locals.
                return(false);
            }

            var           previousMethod = (MethodSymbol)methodEntry.PreviousMethod;
            var           methodIndex    = (uint)MetadataTokens.GetRowNumber(handle);
            SymbolMatcher map;

            // Check if method has changed previously. If so, we already have a map.
            if (baseline.LocalsForMethodsAddedOrChanged.TryGetValue(methodIndex, out previousLocals))
            {
                map = this.mapToPrevious;
            }
            else
            {
                // Method has not changed since initial generation. Generate a map
                // using the local names provided with the initial metadata.
                var localNames = baseline.LocalNames(methodIndex);
                Debug.Assert(!localNames.IsDefault);

                var localInfo = default(ImmutableArray <MetadataDecoder.LocalInfo>);
                try
                {
                    Debug.Assert(this.module.HasIL);
                    var methodIL = this.module.GetMethodILOrThrow(handle);

                    if (!methodIL.LocalSignature.IsNil)
                    {
                        var signature = this.module.MetadataReader.GetLocalSignature(methodIL.LocalSignature);
                        localInfo = this.metadataDecoder.DecodeLocalSignatureOrThrow(signature);
                    }
                    else
                    {
                        localInfo = ImmutableArray <MetadataDecoder.LocalInfo> .Empty;
                    }
                }
                catch (UnsupportedSignatureContent)
                {
                }
                catch (BadImageFormatException)
                {
                }

                if (localInfo.IsDefault)
                {
                    // TODO: Report error that metadata is not supported.
                    return(false);
                }
                else
                {
                    // The signature may have more locals than names if trailing locals are unnamed.
                    // (Locals in the middle of the signature may be unnamed too but since localNames
                    // is indexed by slot, unnamed locals before the last named local will be represented
                    // as null values in the array.)
                    Debug.Assert(localInfo.Length >= localNames.Length);
                    previousLocals = GetLocalSlots(previousMethod, localNames, localInfo);
                    Debug.Assert(previousLocals.Length == localInfo.Length);
                }

                map = this.mapToMetadata;
            }

            // Find declarators in previous method syntax.
            // The locals are indices into this list.
            var previousDeclarators = GetLocalVariableDeclaratorsVisitor.GetDeclarators(previousMethod);

            // Create a map from declarator to declarator offset.
            var previousDeclaratorToOffset = new Dictionary <SyntaxNode, int>();

            for (int offset = 0; offset < previousDeclarators.Length; offset++)
            {
                previousDeclaratorToOffset.Add(previousDeclarators[offset], offset);
            }

            // Create a map from local info to slot.
            var previousLocalInfoToSlot = new Dictionary <Microsoft.CodeAnalysis.Emit.EncLocalInfo, int>();

            for (int slot = 0; slot < previousLocals.Length; slot++)
            {
                var localInfo = previousLocals[slot];
                Debug.Assert(!localInfo.IsDefault);
                if (localInfo.IsInvalid)
                {
                    // Unrecognized or deleted local.
                    continue;
                }
                previousLocalInfoToSlot.Add(localInfo, slot);
            }

            var syntaxMap = methodEntry.SyntaxMap;

            if (syntaxMap == null)
            {
                // If there was no syntax map, the syntax structure has not changed,
                // so we can map from current to previous syntax by declarator index.
                Debug.Assert(methodEntry.PreserveLocalVariables);
                // Create a map from declarator to declarator index.
                var currentDeclarators       = GetLocalVariableDeclaratorsVisitor.GetDeclarators((MethodSymbol)method);
                var currentDeclaratorToIndex = CreateDeclaratorToIndexMap(currentDeclarators);
                syntaxMap = currentSyntax =>
                {
                    var currentIndex = currentDeclaratorToIndex[(CSharpSyntaxNode)currentSyntax];
                    return(previousDeclarators[currentIndex]);
                };
            }

            getPreviousLocalSlot = (object identity, Cci.ITypeReference typeRef, LocalSlotConstraints constraints) =>
            {
                var local      = (LocalSymbol)identity;
                var syntaxRefs = local.DeclaringSyntaxReferences;
                Debug.Assert(!syntaxRefs.IsDefault);

                if (!syntaxRefs.IsDefaultOrEmpty)
                {
                    var currentSyntax  = syntaxRefs[0].GetSyntax();
                    var previousSyntax = (CSharpSyntaxNode)syntaxMap(currentSyntax);
                    if (previousSyntax != null)
                    {
                        int offset;
                        if (previousDeclaratorToOffset.TryGetValue(previousSyntax, out offset))
                        {
                            var previousType = map.MapReference(typeRef);
                            if (previousType != null)
                            {
                                var localKey = new Microsoft.CodeAnalysis.Emit.EncLocalInfo(offset, previousType, constraints, (int)local.TempKind);
                                int slot;
                                // Should report a warning if the type of the local has changed
                                // and the previous value will be dropped. (Bug #781309.)
                                if (previousLocalInfoToSlot.TryGetValue(localKey, out slot))
                                {
                                    return(slot);
                                }
                            }
                        }
                    }
                }

                return(-1);
            };
            return(true);
        }
Esempio n. 8
0
            private void AddLocal(TempKind tempKind)
            {
                var info = this.localInfo[this.slotIndex];

                // We do not emit custom modifiers on locals so ignore the
                // previous version of the local if it had custom modifiers.
                if (info.CustomModifiers.IsDefaultOrEmpty)
                {
                    var constraints = GetConstraints(info);
                    var local = new Microsoft.CodeAnalysis.Emit.EncLocalInfo(this.offset, (Cci.ITypeReference)info.Type, constraints, (int)tempKind);
                    this.locals.Add(local, this.slotIndex);
                }

                this.slotIndex++;
            }
Esempio n. 9
0
        /// <summary>
        /// Match local declarations to names to generate a map from
        /// declaration to local slot. The names are indexed by slot and the
        /// assumption is that declarations are in the same order as slots.
        /// </summary>
        private static ImmutableArray<Microsoft.CodeAnalysis.Emit.EncLocalInfo> GetLocalSlots(
            MethodSymbol method,
            ImmutableArray<string> localNames,
            ImmutableArray<MetadataDecoder.LocalInfo> localInfo)
        {
            var syntaxRefs = method.DeclaringSyntaxReferences;

            // No syntax refs for synthesized methods.
            if (syntaxRefs.Length == 0)
            {
                return ImmutableArray<Microsoft.CodeAnalysis.Emit.EncLocalInfo>.Empty;
            }

            var syntax = syntaxRefs[0].GetSyntax();
            var map = new Dictionary<Microsoft.CodeAnalysis.Emit.EncLocalInfo, int>();
            var visitor = new GetLocalsVisitor(localNames, localInfo, map);
            visitor.Visit(syntax);
            var locals = new Microsoft.CodeAnalysis.Emit.EncLocalInfo[localInfo.Length];
            foreach (var pair in map)
            {
                locals[pair.Value] = pair.Key;
            }

            // Populate any remaining locals that were not matched to source.
            for (int i = 0; i < locals.Length; i++)
            {
                if (locals[i].IsDefault)
                {
                    var info = localInfo[i];
                    var constraints = GetConstraints(info);
                    locals[i] = new Microsoft.CodeAnalysis.Emit.EncLocalInfo((Cci.ITypeReference)info.Type, constraints);
                }
            }

            return ImmutableArray.Create(locals);
        }
Esempio n. 10
0
        internal override bool TryGetPreviousLocals(
            Microsoft.CodeAnalysis.Emit.EmitBaseline baseline,
            IMethodSymbol method,
            out ImmutableArray<Microsoft.CodeAnalysis.Emit.EncLocalInfo> previousLocals,
            out GetPreviousLocalSlot getPreviousLocalSlot)
        {
            previousLocals = default(ImmutableArray<Microsoft.CodeAnalysis.Emit.EncLocalInfo>);
            getPreviousLocalSlot = NoPreviousLocalSlot;

            MethodHandle handle;
            if (!this.TryGetMethodHandle(baseline, (Cci.IMethodDefinition)method, out handle))
            {
                // Unrecognized method. Must have been added in the current compilation.
                return false;
            }

            MethodDefinitionEntry methodEntry;
            if (!this.methodMap.TryGetValue((MethodSymbol)method, out methodEntry))
            {
                // Not part of changeset. No need to preserve locals.
                return false;
            }

            if (!methodEntry.PreserveLocalVariables)
            {
                // Not necessary to preserve locals.
                return false;
            }

            var previousMethod = (MethodSymbol)methodEntry.PreviousMethod;
            var methodIndex = (uint)MetadataTokens.GetRowNumber(handle);
            SymbolMatcher map;

            // Check if method has changed previously. If so, we already have a map.
            if (baseline.LocalsForMethodsAddedOrChanged.TryGetValue(methodIndex, out previousLocals))
            {
                map = this.mapToPrevious;
            }
            else
            {
                // Method has not changed since initial generation. Generate a map
                // using the local names provided with the initial metadata.
                var localNames = baseline.LocalNames(methodIndex);
                Debug.Assert(!localNames.IsDefault);

                var localInfo = default(ImmutableArray<MetadataDecoder.LocalInfo>);
                try
                {
                    Debug.Assert(this.module.HasIL);
                    var methodIL = this.module.GetMethodILOrThrow(handle);

                    if (!methodIL.LocalSignature.IsNil)
                    {
                        var signature = this.module.MetadataReader.GetLocalSignature(methodIL.LocalSignature);
                        localInfo = this.metadataDecoder.DecodeLocalSignatureOrThrow(signature);
                    }
                    else
                    {
                        localInfo = ImmutableArray<MetadataDecoder.LocalInfo>.Empty;
                    }
                }
                catch (UnsupportedSignatureContent)
                {
                }
                catch (BadImageFormatException)
                {
                }

                if (localInfo.IsDefault)
                {
                    // TODO: Report error that metadata is not supported.
                    return false;
                }
                else
                {
                    // The signature may have more locals than names if trailing locals are unnamed.
                    // (Locals in the middle of the signature may be unnamed too but since localNames
                    // is indexed by slot, unnamed locals before the last named local will be represented
                    // as null values in the array.)
                    Debug.Assert(localInfo.Length >= localNames.Length);
                    previousLocals = GetLocalSlots(previousMethod, localNames, localInfo);
                    Debug.Assert(previousLocals.Length == localInfo.Length);
                }

                map = this.mapToMetadata;
            }

            // Find declarators in previous method syntax.
            // The locals are indices into this list.
            var previousDeclarators = GetLocalVariableDeclaratorsVisitor.GetDeclarators(previousMethod);

            // Create a map from declarator to declarator offset.
            var previousDeclaratorToOffset = new Dictionary<SyntaxNode, int>();
            for (int offset = 0; offset < previousDeclarators.Length; offset++)
            {
                previousDeclaratorToOffset.Add(previousDeclarators[offset], offset);
            }

            // Create a map from local info to slot.
            var previousLocalInfoToSlot = new Dictionary<Microsoft.CodeAnalysis.Emit.EncLocalInfo, int>();
            for (int slot = 0; slot < previousLocals.Length; slot++)
            {
                var localInfo = previousLocals[slot];
                Debug.Assert(!localInfo.IsDefault);
                if (localInfo.IsInvalid)
                {
                    // Unrecognized or deleted local.
                    continue;
                }
                previousLocalInfoToSlot.Add(localInfo, slot);
            }

            var syntaxMap = methodEntry.SyntaxMap;
            if (syntaxMap == null)
            {
                // If there was no syntax map, the syntax structure has not changed,
                // so we can map from current to previous syntax by declarator index.
                Debug.Assert(methodEntry.PreserveLocalVariables);
                // Create a map from declarator to declarator index.
                var currentDeclarators = GetLocalVariableDeclaratorsVisitor.GetDeclarators((MethodSymbol)method);
                var currentDeclaratorToIndex = CreateDeclaratorToIndexMap(currentDeclarators);
                syntaxMap = currentSyntax =>
                        {
                            var currentIndex = currentDeclaratorToIndex[(CSharpSyntaxNode)currentSyntax];
                            return previousDeclarators[currentIndex];
                        };
            }

            getPreviousLocalSlot = (object identity, Cci.ITypeReference typeRef, LocalSlotConstraints constraints) =>
                {
                    var local = (LocalSymbol)identity;
                    var syntaxRefs = local.DeclaringSyntaxReferences;
                    Debug.Assert(!syntaxRefs.IsDefault);

                    if (!syntaxRefs.IsDefaultOrEmpty)
                    {
                        var currentSyntax = syntaxRefs[0].GetSyntax();
                        var previousSyntax = (CSharpSyntaxNode)syntaxMap(currentSyntax);
                        if (previousSyntax != null)
                        {
                            int offset;
                            if (previousDeclaratorToOffset.TryGetValue(previousSyntax, out offset))
                            {
                                var previousType = map.MapReference(typeRef);
                                if (previousType != null)
                                {
                                    var localKey = new Microsoft.CodeAnalysis.Emit.EncLocalInfo(offset, previousType, constraints, (int)local.TempKind);
                                    int slot;
                                    // Should report a warning if the type of the local has changed
                                    // and the previous value will be dropped. (Bug #781309.)
                                    if (previousLocalInfoToSlot.TryGetValue(localKey, out slot))
                                    {
                                        return slot;
                                    }
                                }
                            }
                        }
                    }

                    return -1;
                };
            return true;
        }