public EncLocalSlotManager(ImmutableArray <EncLocalInfo> previousLocals, GetPreviousLocalSlot getPreviousLocalSlot) { this.allLocals = new List <LocalDefinition>(); this.getPreviousLocalSlot = getPreviousLocalSlot; // Add placeholders for previous locals. The actual // identities are populated if/when the locals are reused. for (int i = 0; i < previousLocals.Length; i++) { var localInfo = previousLocals[i]; Debug.Assert(localInfo.Type != null); var local = new LocalDefinition( identity: null, name: null, type: localInfo.Type, slot: i, isCompilerGenerated: true, // The placeholder local is marked as compiler-generated // so it will be excluded from the PDB and debugger if not // replaced by a valid local in DeclareLocalInternal. constraints: localInfo.Constraints, isDynamic: false, dynamicTransformFlags: default(ImmutableArray <TypedConstant>)); this.allLocals.Add(local); } }
public EncLocalSlotManager(ImmutableArray<EncLocalInfo> previousLocals, GetPreviousLocalSlot getPreviousLocalSlot) { this.allLocals = new List<LocalDefinition>(); this.getPreviousLocalSlot = getPreviousLocalSlot; // Add placeholders for previous locals. The actual // identities are populated if/when the locals are reused. for (int i = 0; i < previousLocals.Length; i++) { var localInfo = previousLocals[i]; Debug.Assert(localInfo.Type != null); var local = new LocalDefinition( identity: null, name: null, type: localInfo.Type, slot: i, isCompilerGenerated: true, // The placeholder local is marked as compiler-generated // so it will be excluded from the PDB and debugger if not // replaced by a valid local in DeclareLocalInternal. constraints: localInfo.Constraints, isDynamic: false, dynamicTransformFlags: default(ImmutableArray<TypedConstant>)); this.allLocals.Add(local); } }
public EncLocalSlotManager(ImmutableArray<EncLocalInfo> previousLocals, GetPreviousLocalSlot getPreviousLocalSlot) { // Add placeholders for previous locals. The actual // identities are populated if/when the locals are reused. this.allLocals = new List<ILocalDefinition>(previousLocals.Select((info, index) => new SignatureOnlyLocalDefinition(info.Signature, index))); this.getPreviousLocalSlot = getPreviousLocalSlot; }
public EncLocalSlotManager(ImmutableArray <EncLocalInfo> previousLocals, GetPreviousLocalSlot getPreviousLocalSlot) { // Add placeholders for previous locals. The actual // identities are populated if/when the locals are reused. this.allLocals = new List <ILocalDefinition>(previousLocals.Select((info, index) => new SignatureOnlyLocalDefinition(info.Signature, index))); this.getPreviousLocalSlot = getPreviousLocalSlot; }
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; }
internal abstract bool TryGetPreviousLocals( EmitBaseline baseline, IMethodSymbol method, out ImmutableArray <EncLocalInfo> previousLocals, out GetPreviousLocalSlot getPreviousLocalSlot);
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 abstract bool TryGetPreviousLocals( EmitBaseline baseline, IMethodSymbol method, out ImmutableArray<EncLocalInfo> previousLocals, out GetPreviousLocalSlot getPreviousLocalSlot);