提交 e74cd1a7 编写于 作者: A Andrew Casey

Consider MVID when testing EC cache validity

Our EvaluationContext cache invalidation computation was consuming the
method token and version, but not the identity of the declaring assembly.
This lead to a strange bug where we would reuse the cache across assembly
boundaries if consecutive breakpoint happened to have the same method
token (each in its own assembly).

I believe this bug existed before I revised the cache invalidation
computation and we were just getting lucky - we used to check the spans
of all containing scopes, which are unlikely to match exactly across
assemblies.
上级 071d2641
...@@ -129,7 +129,7 @@ internal sealed class EvaluationContext : EvaluationContextBase ...@@ -129,7 +129,7 @@ internal sealed class EvaluationContext : EvaluationContextBase
var previousContext = previous.EvaluationContext; var previousContext = previous.EvaluationContext;
if (previousContext != null && if (previousContext != null &&
previousContext.MethodContextReuseConstraints.HasValue && previousContext.MethodContextReuseConstraints.HasValue &&
previousContext.MethodContextReuseConstraints.GetValueOrDefault().AreSatisfied(methodToken, methodVersion, ilOffset)) previousContext.MethodContextReuseConstraints.GetValueOrDefault().AreSatisfied(moduleVersionId, methodToken, methodVersion, ilOffset))
{ {
return previousContext; return previousContext;
} }
...@@ -144,7 +144,7 @@ internal sealed class EvaluationContext : EvaluationContextBase ...@@ -144,7 +144,7 @@ internal sealed class EvaluationContext : EvaluationContextBase
var allScopes = ArrayBuilder<ISymUnmanagedScope>.GetInstance(); var allScopes = ArrayBuilder<ISymUnmanagedScope>.GetInstance();
var containingScopes = ArrayBuilder<ISymUnmanagedScope>.GetInstance(); var containingScopes = ArrayBuilder<ISymUnmanagedScope>.GetInstance();
typedSymReader.GetScopes(methodToken, methodVersion, ilOffset, IsLocalScopeEndInclusive, allScopes, containingScopes); typedSymReader.GetScopes(methodToken, methodVersion, ilOffset, IsLocalScopeEndInclusive, allScopes, containingScopes);
var methodContextReuseConstraints = allScopes.GetReuseConstraints(methodToken, methodVersion, ilOffset, IsLocalScopeEndInclusive); var methodContextReuseConstraints = allScopes.GetReuseConstraints(moduleVersionId, methodToken, methodVersion, ilOffset, IsLocalScopeEndInclusive);
allScopes.Free(); allScopes.Free();
var localNames = containingScopes.GetLocalNames(); var localNames = containingScopes.GetLocalNames();
......
...@@ -374,7 +374,7 @@ static void G() ...@@ -374,7 +374,7 @@ static void G()
var constraints = previous.EvaluationContext.MethodContextReuseConstraints; var constraints = previous.EvaluationContext.MethodContextReuseConstraints;
if (constraints.HasValue) if (constraints.HasValue)
{ {
Assert.Equal(scope == previousScope, constraints.GetValueOrDefault().AreSatisfied(methodToken, methodVersion, offset)); Assert.Equal(scope == previousScope, constraints.GetValueOrDefault().AreSatisfied(moduleVersionId, methodToken, methodVersion, offset));
} }
context = EvaluationContext.CreateMethodContext(previous, methodBlocks, symReader, moduleVersionId, methodToken, methodVersion, offset, localSignatureToken); context = EvaluationContext.CreateMethodContext(previous, methodBlocks, symReader, moduleVersionId, methodToken, methodVersion, offset, localSignatureToken);
...@@ -405,7 +405,7 @@ static void G() ...@@ -405,7 +405,7 @@ static void G()
// Different references. No reuse. // Different references. No reuse.
context = EvaluationContext.CreateMethodContext(previous, methodBlocks, symReader, moduleVersionId, methodToken, methodVersion, endOffset, localSignatureToken); context = EvaluationContext.CreateMethodContext(previous, methodBlocks, symReader, moduleVersionId, methodToken, methodVersion, endOffset, localSignatureToken);
Assert.NotEqual(context, previous.EvaluationContext); Assert.NotEqual(context, previous.EvaluationContext);
Assert.True(previous.EvaluationContext.MethodContextReuseConstraints.Value.AreSatisfied(methodToken, methodVersion, endOffset)); Assert.True(previous.EvaluationContext.MethodContextReuseConstraints.Value.AreSatisfied(moduleVersionId, methodToken, methodVersion, endOffset));
Assert.NotEqual(context.Compilation, previous.Compilation); Assert.NotEqual(context.Compilation, previous.Compilation);
previous = new CSharpMetadataContext(context); previous = new CSharpMetadataContext(context);
...@@ -413,7 +413,7 @@ static void G() ...@@ -413,7 +413,7 @@ static void G()
GetContextState(runtime, "C.G", out methodBlocks, out moduleVersionId, out symReader, out methodToken, out localSignatureToken); GetContextState(runtime, "C.G", out methodBlocks, out moduleVersionId, out symReader, out methodToken, out localSignatureToken);
context = EvaluationContext.CreateMethodContext(previous, methodBlocks, symReader, moduleVersionId, methodToken, methodVersion, ilOffset: 0, localSignatureToken: localSignatureToken); context = EvaluationContext.CreateMethodContext(previous, methodBlocks, symReader, moduleVersionId, methodToken, methodVersion, ilOffset: 0, localSignatureToken: localSignatureToken);
Assert.NotEqual(context, previous.EvaluationContext); Assert.NotEqual(context, previous.EvaluationContext);
Assert.False(previous.EvaluationContext.MethodContextReuseConstraints.Value.AreSatisfied(methodToken, methodVersion, 0)); Assert.False(previous.EvaluationContext.MethodContextReuseConstraints.Value.AreSatisfied(moduleVersionId, methodToken, methodVersion, 0));
Assert.Equal(context.Compilation, previous.Compilation); Assert.Equal(context.Compilation, previous.Compilation);
// No EvaluationContext. Should reuse Compilation // No EvaluationContext. Should reuse Compilation
......
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Microsoft.CodeAnalysis.ExpressionEvaluator; using Microsoft.CodeAnalysis.ExpressionEvaluator;
using Xunit; using Xunit;
...@@ -10,33 +11,37 @@ public class MethodContextReuseConstraintsTests : ExpressionCompilerTestBase ...@@ -10,33 +11,37 @@ public class MethodContextReuseConstraintsTests : ExpressionCompilerTestBase
[Fact] [Fact]
public void AreSatisfied() public void AreSatisfied()
{ {
var moduleVersionId = Guid.NewGuid();
const int methodToken = 0x06000001; const int methodToken = 0x06000001;
const int methodVersion = 1; const int methodVersion = 1;
const uint startOffset = 1; const uint startOffset = 1;
const uint endOffsetExclusive = 3; const uint endOffsetExclusive = 3;
var constraints = MethodContextReuseConstraints.CreateTestInstance( var constraints = MethodContextReuseConstraints.CreateTestInstance(
moduleVersionId,
methodToken, methodToken,
methodVersion, methodVersion,
startOffset, startOffset,
endOffsetExclusive); endOffsetExclusive);
Assert.True(constraints.AreSatisfied(methodToken, methodVersion, (int)startOffset)); Assert.True(constraints.AreSatisfied(moduleVersionId, methodToken, methodVersion, (int)startOffset));
Assert.True(constraints.AreSatisfied(methodToken, methodVersion, (int)endOffsetExclusive - 1)); Assert.True(constraints.AreSatisfied(moduleVersionId, methodToken, methodVersion, (int)endOffsetExclusive - 1));
Assert.False(constraints.AreSatisfied(methodToken + 1, methodVersion, (int)startOffset)); Assert.False(constraints.AreSatisfied(Guid.NewGuid(), methodToken, methodVersion, (int)startOffset));
Assert.False(constraints.AreSatisfied(methodToken, methodVersion + 1, (int)startOffset)); Assert.False(constraints.AreSatisfied(moduleVersionId, methodToken + 1, methodVersion, (int)startOffset));
Assert.False(constraints.AreSatisfied(methodToken, methodVersion, (int)startOffset - 1)); Assert.False(constraints.AreSatisfied(moduleVersionId, methodToken, methodVersion + 1, (int)startOffset));
Assert.False(constraints.AreSatisfied(methodToken, methodVersion, (int)endOffsetExclusive)); Assert.False(constraints.AreSatisfied(moduleVersionId, methodToken, methodVersion, (int)startOffset - 1));
Assert.False(constraints.AreSatisfied(moduleVersionId, methodToken, methodVersion, (int)endOffsetExclusive));
} }
[Fact] [Fact]
public void EndInclusive() public void EndInclusive()
{ {
var moduleVersionId = Guid.NewGuid();
const int methodToken = 0x06000001; const int methodToken = 0x06000001;
const int methodVersion = 1; const int methodVersion = 1;
var builder = new MethodContextReuseConstraints.Builder(methodToken, methodVersion, ilOffset: 5, areRangesEndInclusive: true); var builder = new MethodContextReuseConstraints.Builder(moduleVersionId, methodToken, methodVersion, ilOffset: 5, areRangesEndInclusive: true);
Assert.True(builder.Build().HasExpectedSpan(0u, uint.MaxValue)); Assert.True(builder.Build().HasExpectedSpan(0u, uint.MaxValue));
builder.AddRange(1, 9); builder.AddRange(1, 9);
...@@ -55,10 +60,11 @@ public void EndInclusive() ...@@ -55,10 +60,11 @@ public void EndInclusive()
[Fact] [Fact]
public void EndExclusive() public void EndExclusive()
{ {
var moduleVersionId = Guid.NewGuid();
const int methodToken = 0x06000001; const int methodToken = 0x06000001;
const int methodVersion = 1; const int methodVersion = 1;
var builder = new MethodContextReuseConstraints.Builder(methodToken, methodVersion, ilOffset: 5, areRangesEndInclusive: false); var builder = new MethodContextReuseConstraints.Builder(moduleVersionId, methodToken, methodVersion, ilOffset: 5, areRangesEndInclusive: false);
Assert.True(builder.Build().HasExpectedSpan(0u, uint.MaxValue)); Assert.True(builder.Build().HasExpectedSpan(0u, uint.MaxValue));
builder.AddRange(1, 9); builder.AddRange(1, 9);
...@@ -77,10 +83,11 @@ public void EndExclusive() ...@@ -77,10 +83,11 @@ public void EndExclusive()
[Fact] [Fact]
public void Cumulative() public void Cumulative()
{ {
var moduleVersionId = Guid.NewGuid();
const int methodToken = 0x06000001; const int methodToken = 0x06000001;
const int methodVersion = 1; const int methodVersion = 1;
var builder = new MethodContextReuseConstraints.Builder(methodToken, methodVersion, ilOffset: 5, areRangesEndInclusive: false); var builder = new MethodContextReuseConstraints.Builder(moduleVersionId, methodToken, methodVersion, ilOffset: 5, areRangesEndInclusive: false);
Assert.True(builder.Build().HasExpectedSpan(0u, uint.MaxValue)); Assert.True(builder.Build().HasExpectedSpan(0u, uint.MaxValue));
builder.AddRange(1, 10); builder.AddRange(1, 10);
......
...@@ -296,9 +296,9 @@ internal static bool IsWindowsAssemblyIdentity(this AssemblyIdentity assemblyIde ...@@ -296,9 +296,9 @@ internal static bool IsWindowsAssemblyIdentity(this AssemblyIdentity assemblyIde
symMethod.GetAllScopes(allScopes, containingScopes, ilOffset, isScopeEndInclusive); symMethod.GetAllScopes(allScopes, containingScopes, ilOffset, isScopeEndInclusive);
} }
internal static MethodContextReuseConstraints GetReuseConstraints(this ArrayBuilder<ISymUnmanagedScope> scopes, int methodToken, int methodVersion, int ilOffset, bool isEndInclusive) internal static MethodContextReuseConstraints GetReuseConstraints(this ArrayBuilder<ISymUnmanagedScope> scopes, Guid moduleVersionId, int methodToken, int methodVersion, int ilOffset, bool isEndInclusive)
{ {
var builder = new MethodContextReuseConstraints.Builder(methodToken, methodVersion, ilOffset, isEndInclusive); var builder = new MethodContextReuseConstraints.Builder(moduleVersionId, methodToken, methodVersion, ilOffset, isEndInclusive);
foreach (ISymUnmanagedScope scope in scopes) foreach (ISymUnmanagedScope scope in scopes)
{ {
builder.AddRange((uint)scope.GetStartOffset(), (uint)scope.GetEndOffset()); builder.AddRange((uint)scope.GetStartOffset(), (uint)scope.GetEndOffset());
......
...@@ -9,34 +9,38 @@ namespace Microsoft.CodeAnalysis.ExpressionEvaluator ...@@ -9,34 +9,38 @@ namespace Microsoft.CodeAnalysis.ExpressionEvaluator
{ {
internal struct MethodContextReuseConstraints internal struct MethodContextReuseConstraints
{ {
private readonly Guid _moduleVersionId;
private readonly int _methodToken; private readonly int _methodToken;
private readonly int _methodVersion; private readonly int _methodVersion;
private readonly uint _startOffset; private readonly uint _startOffset;
private readonly uint _endOffsetExclusive; private readonly uint _endOffsetExclusive;
private MethodContextReuseConstraints(int methodToken, int methodVersion, uint startOffset, uint endOffsetExclusive) private MethodContextReuseConstraints(Guid moduleVersionId, int methodToken, int methodVersion, uint startOffset, uint endOffsetExclusive)
{ {
Debug.Assert(moduleVersionId != default(Guid));
Debug.Assert(MetadataTokens.Handle(methodToken).Kind == HandleKind.MethodDefinition); Debug.Assert(MetadataTokens.Handle(methodToken).Kind == HandleKind.MethodDefinition);
Debug.Assert(methodVersion >= 1); Debug.Assert(methodVersion >= 1);
Debug.Assert(startOffset <= endOffsetExclusive); Debug.Assert(startOffset <= endOffsetExclusive);
_moduleVersionId = moduleVersionId;
_methodToken = methodToken; _methodToken = methodToken;
_methodVersion = methodVersion; _methodVersion = methodVersion;
_startOffset = startOffset; _startOffset = startOffset;
_endOffsetExclusive = endOffsetExclusive; _endOffsetExclusive = endOffsetExclusive;
} }
public bool AreSatisfied(int methodToken, int methodVersion, int ilOffset) public bool AreSatisfied(Guid moduleVersionId, int methodToken, int methodVersion, int ilOffset)
{ {
return methodToken == _methodToken && return moduleVersionId == _moduleVersionId &&
methodToken == _methodToken &&
methodVersion == _methodVersion && methodVersion == _methodVersion &&
ilOffset >= _startOffset && ilOffset >= _startOffset &&
ilOffset < _endOffsetExclusive; ilOffset < _endOffsetExclusive;
} }
internal static MethodContextReuseConstraints CreateTestInstance(int methodToken, int methodVersion, uint startOffset, uint endOffsetExclusive) internal static MethodContextReuseConstraints CreateTestInstance(Guid moduleVersionId, int methodToken, int methodVersion, uint startOffset, uint endOffsetExclusive)
{ {
return new MethodContextReuseConstraints(methodToken, methodVersion, startOffset, endOffsetExclusive); return new MethodContextReuseConstraints(moduleVersionId, methodToken, methodVersion, startOffset, endOffsetExclusive);
} }
internal bool HasExpectedSpan(uint startOffset, uint endOffsetExclusive) internal bool HasExpectedSpan(uint startOffset, uint endOffsetExclusive)
...@@ -46,11 +50,12 @@ internal bool HasExpectedSpan(uint startOffset, uint endOffsetExclusive) ...@@ -46,11 +50,12 @@ internal bool HasExpectedSpan(uint startOffset, uint endOffsetExclusive)
public override string ToString() public override string ToString()
{ {
return $"0x{_methodToken:x8}v{_methodVersion} [{_startOffset}, {_endOffsetExclusive})"; return $"0x{_methodToken:x8}v{_methodVersion} from {_moduleVersionId} [{_startOffset}, {_endOffsetExclusive})";
} }
public class Builder public class Builder
{ {
private readonly Guid _moduleVersionId;
private readonly int _methodToken; private readonly int _methodToken;
private readonly int _methodVersion; private readonly int _methodVersion;
private readonly int _ilOffset; private readonly int _ilOffset;
...@@ -59,12 +64,14 @@ public class Builder ...@@ -59,12 +64,14 @@ public class Builder
private uint _startOffset; private uint _startOffset;
private uint _endOffsetExclusive; private uint _endOffsetExclusive;
public Builder(int methodToken, int methodVersion, int ilOffset, bool areRangesEndInclusive) public Builder(Guid moduleVersionId, int methodToken, int methodVersion, int ilOffset, bool areRangesEndInclusive)
{ {
Debug.Assert(moduleVersionId != default(Guid));
Debug.Assert(MetadataTokens.Handle(methodToken).Kind == HandleKind.MethodDefinition); Debug.Assert(MetadataTokens.Handle(methodToken).Kind == HandleKind.MethodDefinition);
Debug.Assert(methodVersion >= 1); Debug.Assert(methodVersion >= 1);
Debug.Assert(ilOffset >= 0); Debug.Assert(ilOffset >= 0);
_moduleVersionId = moduleVersionId;
_methodToken = methodToken; _methodToken = methodToken;
_methodVersion = methodVersion; _methodVersion = methodVersion;
_ilOffset = ilOffset; _ilOffset = ilOffset;
...@@ -76,6 +83,7 @@ public Builder(int methodToken, int methodVersion, int ilOffset, bool areRangesE ...@@ -76,6 +83,7 @@ public Builder(int methodToken, int methodVersion, int ilOffset, bool areRangesE
public Builder(MethodContextReuseConstraints existingConstraints, int ilOffset, bool areRangesEndInclusive) public Builder(MethodContextReuseConstraints existingConstraints, int ilOffset, bool areRangesEndInclusive)
{ {
_moduleVersionId = existingConstraints._moduleVersionId;
_methodToken = existingConstraints._methodToken; _methodToken = existingConstraints._methodToken;
_methodVersion = existingConstraints._methodVersion; _methodVersion = existingConstraints._methodVersion;
_ilOffset = ilOffset; _ilOffset = ilOffset;
...@@ -111,6 +119,7 @@ public void AddRange(uint startOffset, uint endOffset) ...@@ -111,6 +119,7 @@ public void AddRange(uint startOffset, uint endOffset)
public MethodContextReuseConstraints Build() public MethodContextReuseConstraints Build()
{ {
return new MethodContextReuseConstraints( return new MethodContextReuseConstraints(
_moduleVersionId,
_methodToken, _methodToken,
_methodVersion, _methodVersion,
_startOffset, _startOffset,
......
...@@ -130,7 +130,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator ...@@ -130,7 +130,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator
Dim previousContext = previous.EvaluationContext Dim previousContext = previous.EvaluationContext
If previousContext IsNot Nothing AndAlso If previousContext IsNot Nothing AndAlso
previousContext.MethodContextReuseConstraints.HasValue AndAlso previousContext.MethodContextReuseConstraints.HasValue AndAlso
previousContext.MethodContextReuseConstraints.GetValueOrDefault().AreSatisfied(methodToken, methodVersion, ilOffset) Then previousContext.MethodContextReuseConstraints.GetValueOrDefault().AreSatisfied(moduleVersionId, methodToken, methodVersion, ilOffset) Then
Return previousContext Return previousContext
End If End If
compilation = previous.Compilation compilation = previous.Compilation
...@@ -142,7 +142,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator ...@@ -142,7 +142,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic.ExpressionEvaluator
Dim allScopes = ArrayBuilder(Of ISymUnmanagedScope).GetInstance() Dim allScopes = ArrayBuilder(Of ISymUnmanagedScope).GetInstance()
Dim containingScopes = ArrayBuilder(Of ISymUnmanagedScope).GetInstance() Dim containingScopes = ArrayBuilder(Of ISymUnmanagedScope).GetInstance()
typedSymReader.GetScopes(methodToken, methodVersion, ilOffset, IsLocalScopeEndInclusive, allScopes, containingScopes) typedSymReader.GetScopes(methodToken, methodVersion, ilOffset, IsLocalScopeEndInclusive, allScopes, containingScopes)
Dim reuseConstraints = allScopes.GetReuseConstraints(methodToken, methodVersion, ilOffset, IsLocalScopeEndInclusive) Dim reuseConstraints = allScopes.GetReuseConstraints(moduleVersionId, methodToken, methodVersion, ilOffset, IsLocalScopeEndInclusive)
allScopes.Free() allScopes.Free()
Dim methodHandle = CType(MetadataTokens.Handle(methodToken), MethodDefinitionHandle) Dim methodHandle = CType(MetadataTokens.Handle(methodToken), MethodDefinitionHandle)
......
...@@ -275,7 +275,7 @@ End Class" ...@@ -275,7 +275,7 @@ End Class"
Dim scope = scopes.GetInnermostScope(offset) Dim scope = scopes.GetInnermostScope(offset)
Dim constraints = previous.EvaluationContext.MethodContextReuseConstraints Dim constraints = previous.EvaluationContext.MethodContextReuseConstraints
If constraints.HasValue Then If constraints.HasValue Then
Assert.Equal(scope Is previousScope, constraints.GetValueOrDefault().AreSatisfied(methodToken, methodVersion, offset)) Assert.Equal(scope Is previousScope, constraints.GetValueOrDefault().AreSatisfied(moduleVersionId, methodToken, methodVersion, offset))
End If End If
context = EvaluationContext.CreateMethodContext(previous, methodBlocks, MakeDummyLazyAssemblyReaders(), symReader, moduleVersionId, methodToken, methodVersion, offset, localSignatureToken) context = EvaluationContext.CreateMethodContext(previous, methodBlocks, MakeDummyLazyAssemblyReaders(), symReader, moduleVersionId, methodToken, methodVersion, offset, localSignatureToken)
...@@ -307,7 +307,7 @@ End Class" ...@@ -307,7 +307,7 @@ End Class"
' Different references. No reuse. ' Different references. No reuse.
context = EvaluationContext.CreateMethodContext(previous, methodBlocks, MakeDummyLazyAssemblyReaders(), symReader, moduleVersionId, methodToken, methodVersion, endOffset - 1, localSignatureToken) context = EvaluationContext.CreateMethodContext(previous, methodBlocks, MakeDummyLazyAssemblyReaders(), symReader, moduleVersionId, methodToken, methodVersion, endOffset - 1, localSignatureToken)
Assert.NotEqual(context, previous.EvaluationContext) Assert.NotEqual(context, previous.EvaluationContext)
Assert.True(previous.EvaluationContext.MethodContextReuseConstraints.Value.AreSatisfied(methodToken, methodVersion, endOffset - 1)) Assert.True(previous.EvaluationContext.MethodContextReuseConstraints.Value.AreSatisfied(moduleVersionId, methodToken, methodVersion, endOffset - 1))
Assert.NotEqual(context.Compilation, previous.Compilation) Assert.NotEqual(context.Compilation, previous.Compilation)
previous = new VisualBasicMetadataContext(context) previous = new VisualBasicMetadataContext(context)
...@@ -315,7 +315,7 @@ End Class" ...@@ -315,7 +315,7 @@ End Class"
GetContextState(runtime, "C.G", methodBlocks, moduleVersionId, symReader, methodToken, localSignatureToken) GetContextState(runtime, "C.G", methodBlocks, moduleVersionId, symReader, methodToken, localSignatureToken)
context = EvaluationContext.CreateMethodContext(previous, methodBlocks, MakeDummyLazyAssemblyReaders(), symReader, moduleVersionId, methodToken, methodVersion, ilOffset:=0, localSignatureToken:=localSignatureToken) context = EvaluationContext.CreateMethodContext(previous, methodBlocks, MakeDummyLazyAssemblyReaders(), symReader, moduleVersionId, methodToken, methodVersion, ilOffset:=0, localSignatureToken:=localSignatureToken)
Assert.NotEqual(context, previous.EvaluationContext) Assert.NotEqual(context, previous.EvaluationContext)
Assert.False(previous.EvaluationContext.MethodContextReuseConstraints.Value.AreSatisfied(methodToken, methodVersion, 0)) Assert.False(previous.EvaluationContext.MethodContextReuseConstraints.Value.AreSatisfied(moduleVersionId, methodToken, methodVersion, 0))
Assert.Equal(context.Compilation, previous.Compilation) Assert.Equal(context.Compilation, previous.Compilation)
' No EvaluationContext. Should reuse Compilation ' No EvaluationContext. Should reuse Compilation
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册