Use a synthesized local for the lockTaken parameter and create a region for it.

上级 d718eb25
......@@ -1726,12 +1726,19 @@ private ILockOperation CreateBoundLockStatementOperation(BoundLockStatement boun
{
Lazy<IOperation> expression = new Lazy<IOperation>(() => Create(boundLockStatement.Argument));
Lazy<IOperation> body = new Lazy<IOperation>(() => Create(boundLockStatement.Body));
// If there is no Enter2 method, then there will be no lock taken reference
bool legacyMode = _semanticModel.Compilation.CommonGetWellKnownTypeMember(WellKnownMember.System_Threading_Monitor__Enter2) == null;
ILocalSymbol lockTakenSymbol =
legacyMode ? null : new SynthesizedLocal(_semanticModel.GetEnclosingSymbol(boundLockStatement.Syntax.SpanStart) as MethodSymbol,
(TypeSymbol)_semanticModel.Compilation.GetSpecialType(SpecialType.System_Boolean),
SynthesizedLocalKind.LockTaken,
syntaxOpt: boundLockStatement.Argument.Syntax);
SyntaxNode syntax = boundLockStatement.Syntax;
ITypeSymbol type = null;
Optional<object> constantValue = default(Optional<object>);
bool isImplicit = boundLockStatement.WasCompilerGenerated;
return new LazyLockStatement(expression, body, _semanticModel, syntax, type, constantValue, isImplicit);
return new LazyLockStatement(expression, body, lockTakenSymbol, _semanticModel, syntax, type, constantValue, isImplicit);
}
private IInvalidOperation CreateBoundBadStatementOperation(BoundBadStatement boundBadStatement)
......
......@@ -3512,9 +3512,10 @@ public override void Accept(OperationVisitor visitor)
/// </summary>
internal abstract partial class BaseLockStatement : Operation, ILockOperation
{
protected BaseLockStatement(SemanticModel semanticModel, SyntaxNode syntax, ITypeSymbol type, Optional<object> constantValue, bool isImplicit) :
protected BaseLockStatement(ILocalSymbol lockTakenSymbol, SemanticModel semanticModel, SyntaxNode syntax, ITypeSymbol type, Optional<object> constantValue, bool isImplicit) :
base(OperationKind.Lock, semanticModel, syntax, type, constantValue, isImplicit)
{
LockTakenSymbol = lockTakenSymbol;
}
public override IEnumerable<IOperation> Children
......@@ -3539,6 +3540,7 @@ public override IEnumerable<IOperation> Children
/// Body of the lock, to be executed while holding the lock.
/// </summary>
public abstract IOperation Body { get; }
public ILocalSymbol LockTakenSymbol { get; }
public override void Accept(OperationVisitor visitor)
{
visitor.VisitLock(this);
......@@ -3554,8 +3556,8 @@ public override void Accept(OperationVisitor visitor)
/// </summary>
internal sealed partial class LockStatement : BaseLockStatement, ILockOperation
{
public LockStatement(IOperation lockedValue, IOperation body, SemanticModel semanticModel, SyntaxNode syntax, ITypeSymbol type, Optional<object> constantValue, bool isImplicit) :
base(semanticModel, syntax, type, constantValue, isImplicit)
public LockStatement(IOperation lockedValue, IOperation body, ILocalSymbol lockTakenSymbol, SemanticModel semanticModel, SyntaxNode syntax, ITypeSymbol type, Optional<object> constantValue, bool isImplicit) :
base(lockTakenSymbol, semanticModel, syntax, type, constantValue, isImplicit)
{
LockedValue = SetParentOperation(lockedValue, this);
Body = SetParentOperation(body, this);
......@@ -3573,8 +3575,8 @@ internal sealed partial class LazyLockStatement : BaseLockStatement, ILockOperat
private readonly Lazy<IOperation> _lazyLockedValue;
private readonly Lazy<IOperation> _lazyBody;
public LazyLockStatement(Lazy<IOperation> lockedValue, Lazy<IOperation> body, SemanticModel semanticModel, SyntaxNode syntax, ITypeSymbol type, Optional<object> constantValue, bool isImplicit) :
base(semanticModel, syntax, type, constantValue, isImplicit)
public LazyLockStatement(Lazy<IOperation> lockedValue, Lazy<IOperation> body, ILocalSymbol lockTakenSymbol, SemanticModel semanticModel, SyntaxNode syntax, ITypeSymbol type, Optional<object> constantValue, bool isImplicit) :
base(lockTakenSymbol, semanticModel, syntax, type, constantValue, isImplicit)
{
_lazyLockedValue = lockedValue ?? throw new System.ArgumentNullException(nameof(lockedValue));
_lazyBody = body ?? throw new System.ArgumentNullException(nameof(body));
......
......@@ -3212,34 +3212,34 @@ public override IOperation VisitLock(ILockOperation operation, int? captureIdFor
// If Monitor.Enter(object, ref bool) is available:
//
// L $lock = `LockedValue`;
// bool $lockTaken = false;
// L $lock = `LockedValue`;
// bool $lockTaken = false;
// try
// {
// Monitor.Enter($lock, ref $lockTaken);
// `body`
// `body`
// }
// finally
// {
// if ($lockTaken) Monitor.Exit($lock);
// {
// if ($lockTaken) Monitor.Exit($lock);
// }
// If Monitor.Enter(object, ref bool) is not available:
//
// L $lock = `LockedValue`;
// Monitor.Enter($lock); // NB: before try-finally so we don't Exit if an exception prevents us from acquiring the lock.
// try
// try
// {
// `body`
// }
// finally
// }
// finally
// {
// Monitor.Exit($lock);
// Monitor.Exit($lock);
// }
// If original type of the LockedValue object is System.Object, VB calls runtime helper (if one is available)
// Microsoft.VisualBasic.CompilerServices.ObjectFlowControl.CheckForSyncLockOnValueType to ensure no value type is
// used.
// Microsoft.VisualBasic.CompilerServices.ObjectFlowControl.CheckForSyncLockOnValueType to ensure no value type is
// used.
// For simplicity, we will not synthesize this call because its presence is unlikely to affect graph analysis.
IOperation lockedValue = Visit(operation.LockedValue);
......@@ -3281,6 +3281,11 @@ public override IOperation VisitLock(ILockOperation operation, int? captureIdFor
enterMethod.ReturnType, constantValue: default, isImplicit: true));
}
}
else
{
var baseLockStatement = (BaseLockStatement)operation;
EnterRegion(new RegionBuilder(ControlFlowRegionKind.LocalLifetime, locals: ImmutableArray.Create(baseLockStatement.LockTakenSymbol)));
}
var afterTryFinally = new BasicBlockBuilder(BasicBlockKind.Block);
......@@ -3291,7 +3296,9 @@ public override IOperation VisitLock(ILockOperation operation, int? captureIdFor
if (!legacyMode)
{
// Monitor.Enter($lock, ref $lockTaken);
lockTaken = new FlowCaptureReference(_captureIdDispenser.GetNextId(), lockedValue.Syntax, _compilation.GetSpecialType(SpecialType.System_Boolean), constantValue: default);
var baseLockStatement = (BaseLockStatement)operation;
lockTaken = new LocalReferenceExpression(baseLockStatement.LockTakenSymbol, isDeclaration: false, semanticModel: null, lockedValue.Syntax,
baseLockStatement.LockTakenSymbol.Type, constantValue: null, isImplicit: true);
AddStatement(new InvocationExpression(enterMethod, instance: null, isVirtual: false,
ImmutableArray.Create<IArgumentOperation>(
new ArgumentOperation(lockedValue,
......@@ -3365,6 +3372,11 @@ public override IOperation VisitLock(ILockOperation operation, int? captureIdFor
LeaveRegion();
Debug.Assert(_currentRegion.Kind == ControlFlowRegionKind.TryAndFinally);
LeaveRegion();
if (!legacyMode)
{
Debug.Assert(_currentRegion.Kind == ControlFlowRegionKind.LocalLifetime);
LeaveRegion();
}
AppendNewBlock(afterTryFinally, linkToPrevious: false);
......
......@@ -153,7 +153,8 @@ public override IOperation VisitReturn(IReturnOperation operation, object argume
public override IOperation VisitLock(ILockOperation operation, object argument)
{
return new LockStatement(Visit(operation.LockedValue), Visit(operation.Body), ((Operation)operation).SemanticModel, operation.Syntax, operation.Type, operation.ConstantValue, operation.IsImplicit);
var baseLockStatement = (BaseLockStatement)operation;
return new LockStatement(Visit(operation.LockedValue), Visit(operation.Body), baseLockStatement.LockTakenSymbol, baseLockStatement.SemanticModel, operation.Syntax, operation.Type, operation.ConstantValue, operation.IsImplicit);
}
public override IOperation VisitTry(ITryOperation operation, object argument)
......
......@@ -1422,11 +1422,18 @@ Namespace Microsoft.CodeAnalysis.Operations
Private Function CreateBoundSyncLockStatementOperation(boundSyncLockStatement As BoundSyncLockStatement) As ILockOperation
Dim expression As Lazy(Of IOperation) = New Lazy(Of IOperation)(Function() Create(boundSyncLockStatement.LockExpression))
Dim body As Lazy(Of IOperation) = New Lazy(Of IOperation)(Function() Create(boundSyncLockStatement.Body))
Dim legacyMode = _semanticModel.Compilation.CommonGetWellKnownTypeMember(WellKnownMember.System_Threading_Monitor__Enter2) Is Nothing
Dim lockTakenSymbol As ILocalSymbol =
If(legacyMode, Nothing,
New SynthesizedLocal(DirectCast(_semanticModel.GetEnclosingSymbol(boundSyncLockStatement.Syntax.SpanStart), Symbol),
DirectCast(_semanticModel.Compilation.GetSpecialType(SpecialType.System_Boolean), TypeSymbol),
SynthesizedLocalKind.LockTaken,
syntaxOpt:=boundSyncLockStatement.LockExpression.Syntax))
Dim syntax As SyntaxNode = boundSyncLockStatement.Syntax
Dim type As ITypeSymbol = Nothing
Dim constantValue As [Optional](Of Object) = New [Optional](Of Object)()
Dim isImplicit As Boolean = boundSyncLockStatement.WasCompilerGenerated
Return New LazyLockStatement(expression, body, _semanticModel, syntax, type, constantValue, isImplicit)
Return New LazyLockStatement(expression, body, lockTakenSymbol, _semanticModel, syntax, type, constantValue, isImplicit)
End Function
Private Function CreateBoundNoOpStatementOperation(boundNoOpStatement As BoundNoOpStatement) As IEmptyOperation
......
......@@ -392,64 +392,68 @@ Block[B1] - Block
ILiteralOperation (OperationKind.Literal, Type: null, Constant: null) (Syntax: 'Nothing')
Next (Regular) Block[B2]
Entering: {R1} {R2}
Entering: {R1} {R2} {R3}
.try {R1, R2}
.locals {R1}
{
Block[B2] - Block
Predecessors: [B1]
Statements (2)
IInvocationOperation (Sub System.Threading.Monitor.Enter(obj As System.Object, ByRef lockTaken As System.Boolean)) (OperationKind.Invocation, Type: System.Void, IsImplicit) (Syntax: 'Nothing')
Instance Receiver:
null
Arguments(2):
IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: obj) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: 'Nothing')
IFlowCaptureReferenceOperation: 0 (OperationKind.FlowCaptureReference, Type: System.Object, Constant: null, IsImplicit) (Syntax: 'Nothing')
InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: lockTaken) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: 'Nothing')
IFlowCaptureReferenceOperation: 1 (OperationKind.FlowCaptureReference, Type: System.Boolean, IsImplicit) (Syntax: 'Nothing')
InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'input = true')
Expression:
ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Boolean, IsImplicit) (Syntax: 'input = true')
Left:
IParameterReferenceOperation: input (OperationKind.ParameterReference, Type: System.Boolean) (Syntax: 'input')
Right:
ILiteralOperation (OperationKind.Literal, Type: System.Boolean, Constant: True) (Syntax: 'true')
Next (Regular) Block[B6]
Finalizing: {R3}
Leaving: {R2} {R1}
}
.finally {R3}
{
Block[B3] - Block
Predecessors (0)
Statements (0)
Jump if False (Regular) to Block[B5]
IFlowCaptureReferenceOperation: 1 (OperationKind.FlowCaptureReference, Type: System.Boolean, IsImplicit) (Syntax: 'Nothing')
Next (Regular) Block[B4]
Block[B4] - Block
Predecessors: [B3]
Statements (1)
IInvocationOperation (Sub System.Threading.Monitor.Exit(obj As System.Object)) (OperationKind.Invocation, Type: System.Void, IsImplicit) (Syntax: 'Nothing')
Instance Receiver:
null
Arguments(1):
IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: obj) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: 'Nothing')
IFlowCaptureReferenceOperation: 0 (OperationKind.FlowCaptureReference, Type: System.Object, Constant: null, IsImplicit) (Syntax: 'Nothing')
InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
Next (Regular) Block[B5]
Block[B5] - Block
Predecessors: [B3] [B4]
Statements (0)
Next (StructuredExceptionHandling) Block[null]
Locals: [<anonymous local> As System.Boolean]
.try {R2, R3}
{
Block[B2] - Block
Predecessors: [B1]
Statements (2)
IInvocationOperation (Sub System.Threading.Monitor.Enter(obj As System.Object, ByRef lockTaken As System.Boolean)) (OperationKind.Invocation, Type: System.Void, IsImplicit) (Syntax: 'Nothing')
Instance Receiver:
null
Arguments(2):
IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: obj) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: 'Nothing')
IFlowCaptureReferenceOperation: 0 (OperationKind.FlowCaptureReference, Type: System.Object, Constant: null, IsImplicit) (Syntax: 'Nothing')
InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: lockTaken) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: 'Nothing')
ILocalReferenceOperation: (OperationKind.LocalReference, Type: System.Boolean, Constant: null, IsImplicit) (Syntax: 'Nothing')
InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
IExpressionStatementOperation (OperationKind.ExpressionStatement, Type: null) (Syntax: 'input = true')
Expression:
ISimpleAssignmentOperation (OperationKind.SimpleAssignment, Type: System.Boolean, IsImplicit) (Syntax: 'input = true')
Left:
IParameterReferenceOperation: input (OperationKind.ParameterReference, Type: System.Boolean) (Syntax: 'input')
Right:
ILiteralOperation (OperationKind.Literal, Type: System.Boolean, Constant: True) (Syntax: 'true')
Next (Regular) Block[B6]
Finalizing: {R4}
Leaving: {R3} {R2} {R1}
}
.finally {R4}
{
Block[B3] - Block
Predecessors (0)
Statements (0)
Jump if False (Regular) to Block[B5]
ILocalReferenceOperation: (OperationKind.LocalReference, Type: System.Boolean, Constant: null, IsImplicit) (Syntax: 'Nothing')
Next (Regular) Block[B4]
Block[B4] - Block
Predecessors: [B3]
Statements (1)
IInvocationOperation (Sub System.Threading.Monitor.Exit(obj As System.Object)) (OperationKind.Invocation, Type: System.Void, IsImplicit) (Syntax: 'Nothing')
Instance Receiver:
null
Arguments(1):
IArgumentOperation (ArgumentKind.Explicit, Matching Parameter: obj) (OperationKind.Argument, Type: null, IsImplicit) (Syntax: 'Nothing')
IFlowCaptureReferenceOperation: 0 (OperationKind.FlowCaptureReference, Type: System.Object, Constant: null, IsImplicit) (Syntax: 'Nothing')
InConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
OutConversion: CommonConversion (Exists: True, IsIdentity: True, IsNumeric: False, IsReference: False, IsUserDefined: False) (MethodSymbol: null)
Next (Regular) Block[B5]
Block[B5] - Block
Predecessors: [B3] [B4]
Statements (0)
Next (StructuredExceptionHandling) Block[null]
}
}
Block[B6] - Exit
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册