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)); }
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); }
/// <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++; }
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)); } }
/// <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); }
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); }
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++; }