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