internal override ImmutableArray <EncLocalInfo> GetLocalInfo( Cci.IMethodDefinition methodDef, ImmutableArray <LocalDefinition> localDefs) { if (localDefs.IsEmpty) { return(ImmutableArray <EncLocalInfo> .Empty); } // Find declarators in current method syntax. var declarators = LocalVariableDeclaratorsCollector.GetDeclarators((MethodSymbol)methodDef); // Create a map from declarator to declarator index. var declaratorToIndex = CreateDeclaratorToIndexMap(declarators); return(localDefs.SelectAsArray(localDef => GetLocalInfo(declaratorToIndex, localDef))); }
public override ImmutableArray <SyntaxNode> GetDeclarators(ISymbol method) { Assert.True(method is MethodSymbol, "Only methods should have a syntax map."); return(LocalVariableDeclaratorsCollector.GetDeclarators((SourceMethodSymbol)method)); }
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); }
internal override VariableSlotAllocator TryCreateVariableSlotAllocator(EmitBaseline baseline, IMethodSymbol method) { MethodHandle handle; if (!this.TryGetMethodHandle(baseline, (Cci.IMethodDefinition)method, out handle)) { // Unrecognized method. Must have been added in the current compilation. return(null); } MethodDefinitionEntry methodEntry; if (!this.methodMap.TryGetValue(method, out methodEntry)) { // Not part of changeset. No need to preserve locals. return(null); } if (!methodEntry.PreserveLocalVariables) { // Not necessary to preserve locals. return(null); } CSharpSymbolMatcher symbolMap; ImmutableArray <EncLocalInfo> previousLocals; uint methodIndex = (uint)MetadataTokens.GetRowNumber(handle); // Check if method has changed previously. If so, we already have a map. if (baseline.LocalsForMethodsAddedOrChanged.TryGetValue(methodIndex, out previousLocals)) { symbolMap = 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(handle); Debug.Assert(!localNames.IsDefault); ImmutableArray <MetadataDecoder.LocalInfo> localInfo; if (!metadataDecoder.TryGetLocals(handle, out localInfo)) { // TODO: Report error that metadata is not supported. return(null); } // 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(methodEntry.PreviousMethod, localNames, localInfo); Debug.Assert(previousLocals.Length == localInfo.Length); symbolMap = this.mapToMetadata; } // Find declarators in previous method syntax. // The locals are indices into this list. var previousDeclarators = LocalVariableDeclaratorsCollector.GetDeclarators(methodEntry.PreviousMethod); 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[currentSyntax]; return(previousDeclarators[currentIndex]); }; } return(new EncVariableSlotAllocator(symbolMap, syntaxMap, previousDeclarators, previousLocals)); }