예제 #1
0
        private static EncLocalInfo MapLocalInfo(
            SymbolMatcher map,
            EncLocalInfo localInfo)
        {
            Debug.Assert(!localInfo.IsDefault);
            var type = map.MapReference(localInfo.Type);

            Debug.Assert(type != null);
            return(new EncLocalInfo(localInfo.Offset, type, localInfo.Constraints, localInfo.TempKind));
        }
예제 #2
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);
        }
예제 #3
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 <EncLocalInfo> CreateLocalSlotMap(
            EditAndContinueMethodDebugInformation methodEncInfo,
            ImmutableArray <LocalInfo <TypeSymbol> > slotMetadata)
        {
            var result = new EncLocalInfo[slotMetadata.Length];

            var localSlots = methodEncInfo.LocalSlots;

            if (!localSlots.IsDefault)
            {
                // In case of corrupted PDB or metadata, these lengths might not match.
                // Let's guard against such case.
                int slotCount = Math.Min(localSlots.Length, slotMetadata.Length);

                var map = new Dictionary <EncLocalInfo, int>();

                for (int slotIndex = 0; slotIndex < slotCount; slotIndex++)
                {
                    var slot = localSlots[slotIndex];
                    if (slot.SynthesizedKind.IsLongLived())
                    {
                        var metadata = slotMetadata[slotIndex];

                        // We do not emit custom modifiers on locals so ignore the
                        // previous version of the local if it had custom modifiers.
                        if (metadata.CustomModifiers.IsDefaultOrEmpty)
                        {
                            var local = new EncLocalInfo(slot, (Cci.ITypeReference)metadata.Type, metadata.Constraints, metadata.SignatureOpt);
                            map.Add(local, slotIndex);
                        }
                    }
                }

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

            // Populate any remaining locals that were not matched to source.
            for (int i = 0; i < result.Length; i++)
            {
                if (result[i].IsDefault)
                {
                    result[i] = new EncLocalInfo(slotMetadata[i].SignatureOpt);
                }
            }

            return(ImmutableArray.Create(result));
        }
            private void AddLocalImpl(ref int slotIndex, SynthesizedLocalKind synthesizedKind)
            {
                var info = this.localInfo[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 local = new EncLocalInfo(this.offset, (Cci.ITypeReference)info.Type, info.Constraints, (CommonSynthesizedLocalKind)synthesizedKind, info.SignatureOpt);
                    this.locals.Add(local, slotIndex);
                }

                slotIndex++;
            }
            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 EncLocalInfo(this.offset, (Cci.ITypeReference)info.Type, constraints, (int)tempKind);
                    this.locals.Add(local, this.slotIndex);
                }

                this.slotIndex++;
            }
예제 #6
0
 private static EncLocalInfo MapLocalInfo(
     CSharpSymbolMatcher map,
     EncLocalInfo localInfo)
 {
     Debug.Assert(!localInfo.IsDefault);
     if (localInfo.Type == null)
     {
         Debug.Assert(localInfo.Signature != null);
         return(localInfo);
     }
     else
     {
         var type = map.MapReference(localInfo.Type);
         Debug.Assert(type != null);
         return(new EncLocalInfo(localInfo.Offset, type, localInfo.Constraints, localInfo.SynthesizedKind, localInfo.Signature));
     }
 }
예제 #7
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<EncLocalInfo> GetLocalSlots(
            IMethodSymbol method,
            ImmutableArray<string> localNames,
            ImmutableArray<MetadataDecoder.LocalInfo> localInfo)
        {
            var syntaxRefs = method.DeclaringSyntaxReferences;

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

            var syntax = syntaxRefs[0].GetSyntax();
            var map = LocalSlotMapBuilder.CreateMap(syntax, localNames, localInfo);
            var locals = new 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 EncLocalInfo((Cci.ITypeReference)info.Type, constraints);
                }
            }

            return ImmutableArray.Create(locals);
        }
예제 #8
0
        internal override bool TryGetPreviousLocals(
            EmitBaseline baseline,
            IMethodSymbol method,
            out ImmutableArray<EncLocalInfo> previousLocals,
            out GetPreviousLocalSlot getPreviousLocalSlot)
        {
            previousLocals = default(ImmutableArray<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(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 = 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 methodBody = this.module.GetMethodBodyOrThrow(handle);

                    if (!methodBody.LocalSignature.IsNil)
                    {
                        var signature = this.module.MetadataReader.GetLocalSignature(methodBody.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 = LocalVariableDeclaratorsCollector.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<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 = LocalVariableDeclaratorsCollector.GetDeclarators(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 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;
        }
        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);
        }
예제 #10
0
        internal override bool TryGetPreviousLocals(
            EmitBaseline baseline,
            IMethodSymbol method,
            out ImmutableArray <EncLocalInfo> previousLocals,
            out GetPreviousLocalSlot getPreviousLocalSlot)
        {
            previousLocals       = default(ImmutableArray <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(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 = 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 methodBody = this.module.GetMethodBodyOrThrow(handle);

                    if (!methodBody.LocalSignature.IsNil)
                    {
                        var signatureHandle = this.module.MetadataReader.GetLocalSignature(methodBody.LocalSignature);
                        var signatureReader = this.module.GetMemoryReaderOrThrow(signatureHandle);
                        localInfo = this.metadataDecoder.DecodeLocalSignatureOrThrow(ref signatureReader);
                    }
                    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 = LocalVariableDeclaratorsCollector.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 <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       = LocalVariableDeclaratorsCollector.GetDeclarators(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 EncLocalInfo(offset, previousType, constraints, (int)local.SynthesizedLocalKind, 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(slot);
                                }
                            }
                        }
                    }
                }

                return(-1);
            };

            return(true);
        }
            private void AddLocalImpl(ref int slotIndex, SynthesizedLocalKind synthesizedKind)
            {
                var info = this.localInfo[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 EncLocalInfo(this.offset, (Cci.ITypeReference)info.Type, constraints, (int)synthesizedKind, info.Signature);
                    this.locals.Add(local, slotIndex);
                }

                slotIndex++;
            }
            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 EncLocalInfo(this.offset, (Cci.ITypeReference)info.Type, constraints, (int)tempKind);
                    this.locals.Add(local, this.slotIndex);
                }

                this.slotIndex++;
            }