Permalink
Switch branches/tags
version-2.9.0 version-2.8.2 version-2.8.0 version-2.7.0-beta3 version-2.6.0-beta3 version-2.4.0 version-2.3.5 version-2.3.4 version-2.3.2 version-2.3.2-beta1 version-2.3.0-beta3 version-2.3.0-beta2 version-2.3.0-beta1 version-2.2.0 version-2.1.0 version-2.0.0 version-2.0.0-rc4 version-2.0.0-rc3 version-2.0.0-rc2 version-2.0.0-rc version-2.0.0-beta5 version-2.0.0-beta4 version-2.0.0-beta3 version-2.0.0-beta1 version-1.3.2 version-1.3.1 version-1.3.0 version-1.3.0-beta1-20160429-01 version-1.2.2 version-1.2.1 version-1.2.0 version-1.2.0-beta1-20160108-01 version-1.2.0-beta version-1.2.0-beta-20151211-01 version-1.1.1 version-1.1.0 version-1.1.0-rc1-20151109-01 version-1.0.0 version-1.0.0-beta1-20141031-01 toolset_5 toolset_3 toolset_2 toolset_1_1 toolset_1 Visual.Studio.2015.Update.1.RC Visual.Studio.2015.Update.1.CTP Visual-Studio-2017 Visual-Studio-2017-Version-15.8 Visual-Studio-2017-Version-15.7.2 Visual-Studio-2017-Version-15.7 Visual-Studio-2017-Version-15.6 Visual-Studio-2017-Version-15.5 Visual-Studio-2017-Version-15.4 Visual-Studio-2017-Version-15.3.5 Visual-Studio-2017-Version-15.3.4 Visual-Studio-2017-Version-15.3.2 Visual-Studio-2017-Version-15.3 Visual-Studio-2017-Version-15.2 Visual-Studio-2017-Version-15.1 Visual-Studio-2017-RC4 Visual-Studio-2017-RC3 Visual-Studio-2017-RC2 Visual-Studio-2017-RC Visual-Studio-2017-Preview-Version-15.3 Visual-Studio-2017-Preview-6-Version-15.7 Visual-Studio-2017-Preview-3-Version-15.4 Visual-Studio-2017-Preview-3-Version-15.3 Visual-Studio-2017-Preview-2-Version-15.4 Visual-Studio-2017-Preview-2-Version-15.3 Visual-Studio-2017-Preview-1-Version-15.4 Visual-Studio-2015 Visual-Studio-2015-Update-3 Visual-Studio-2015-Update-3-Micro-Update-1 Visual-Studio-2015-Update-2 Visual-Studio-2015-Update-2-RC Visual-Studio-2015-Update-2-Micro-Update-3 Visual-Studio-2015-Update-2-Micro-Update-1 Visual-Studio-2015-Update-1 Visual-Studio-2015-Update-1-RC Visual-Studio-2015-Update-1-CTP Visual-Studio-2015-RC Visual-Studio-2015-Preview Visual-Studio-2015-CTP-6 Visual-Studio-2015-CTP-5 Visual-Studio-15-Preview Visual-Studio-15-Preview-5 Visual-Studio-15-Preview-4 Visual-Studio-15-Preview-3 VS.Toolset.Roslyn.1.1.0-beta1-20150727-01 VS.Tools.X86.Managed.V45.1.0.150513.2 Oss.Scan.2015.03.13 Oss.Scan.2013.03.13 NetFx.Toolset.150729
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
192 lines (167 sloc) 8.59 KB
// 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.Collections.Immutable;
using System.Diagnostics;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Text;
namespace Microsoft.CodeAnalysis.CSharp
{
internal sealed partial class LocalRewriter
{
/// <summary>
/// Lowers a lock statement to a try-finally block that calls Monitor.Enter and Monitor.Exit
/// before and after the body, respectively.
/// </summary>
public override BoundNode VisitLockStatement(BoundLockStatement node)
{
LockStatementSyntax lockSyntax = (LockStatementSyntax)node.Syntax;
BoundExpression rewrittenArgument = VisitExpression(node.Argument);
BoundStatement rewrittenBody = (BoundStatement)Visit(node.Body);
TypeSymbol argumentType = rewrittenArgument.Type;
if ((object)argumentType == null)
{
// This isn't particularly elegant, but hopefully locking on null is
// not very common.
Debug.Assert(rewrittenArgument.ConstantValue == ConstantValue.Null);
argumentType = _compilation.GetSpecialType(SpecialType.System_Object);
rewrittenArgument = MakeLiteral(
rewrittenArgument.Syntax,
rewrittenArgument.ConstantValue,
argumentType); //need to have a non-null type here for TempHelpers.StoreToTemp.
}
if (argumentType.Kind == SymbolKind.TypeParameter)
{
// If the argument has a type parameter type, then we'll box it right away
// so that the same object is passed to both Monitor.Enter and Monitor.Exit.
argumentType = _compilation.GetSpecialType(SpecialType.System_Object);
rewrittenArgument = MakeConversionNode(
rewrittenArgument.Syntax,
rewrittenArgument,
Conversion.Boxing,
argumentType,
@checked: false,
constantValueOpt: rewrittenArgument.ConstantValue);
}
BoundAssignmentOperator assignmentToLockTemp;
BoundLocal boundLockTemp = _factory.StoreToTemp(rewrittenArgument, out assignmentToLockTemp, syntaxOpt: lockSyntax, kind: SynthesizedLocalKind.Lock);
BoundStatement boundLockTempInit = new BoundExpressionStatement(lockSyntax, assignmentToLockTemp);
BoundExpression exitCallExpr;
MethodSymbol exitMethod;
if (TryGetWellKnownTypeMember(lockSyntax, WellKnownMember.System_Threading_Monitor__Exit, out exitMethod))
{
exitCallExpr = BoundCall.Synthesized(
lockSyntax,
null,
exitMethod,
boundLockTemp);
}
else
{
exitCallExpr = new BoundBadExpression(lockSyntax, LookupResultKind.NotInvocable, ImmutableArray<Symbol>.Empty, ImmutableArray.Create<BoundExpression>(boundLockTemp), ErrorTypeSymbol.UnknownResultType);
}
BoundStatement exitCall = new BoundExpressionStatement(lockSyntax, exitCallExpr);
MethodSymbol enterMethod;
if ((TryGetWellKnownTypeMember(lockSyntax, WellKnownMember.System_Threading_Monitor__Enter2, out enterMethod, isOptional: true) ||
TryGetWellKnownTypeMember(lockSyntax, WellKnownMember.System_Threading_Monitor__Enter, out enterMethod)) && // If we didn't find the overload introduced in .NET 4.0, then use the older one.
enterMethod.ParameterCount == 2)
{
// C# 4.0+ version
// L $lock = `argument`; // sequence point
// bool $lockTaken = false;
// try
// {
// Monitor.Enter($lock, ref $lockTaken);
// `body` // sequence point
// }
// finally
// { // hidden sequence point
// if ($lockTaken) Monitor.Exit($lock);
// }
TypeSymbol boolType = _compilation.GetSpecialType(SpecialType.System_Boolean);
BoundAssignmentOperator assignmentToLockTakenTemp;
BoundLocal boundLockTakenTemp = _factory.StoreToTemp(
MakeLiteral(rewrittenArgument.Syntax, ConstantValue.False, boolType),
store: out assignmentToLockTakenTemp,
syntaxOpt: lockSyntax,
kind: SynthesizedLocalKind.LockTaken);
BoundStatement boundLockTakenTempInit = new BoundExpressionStatement(lockSyntax, assignmentToLockTakenTemp);
BoundStatement enterCall = new BoundExpressionStatement(
lockSyntax,
BoundCall.Synthesized(
lockSyntax,
null,
enterMethod,
boundLockTemp,
boundLockTakenTemp));
exitCall = RewriteIfStatement(
lockSyntax,
boundLockTakenTemp,
exitCall,
null,
node.HasErrors);
return new BoundBlock(
lockSyntax,
ImmutableArray.Create(boundLockTemp.LocalSymbol, boundLockTakenTemp.LocalSymbol),
ImmutableArray.Create(
InstrumentLockTargetCapture(node, boundLockTempInit),
boundLockTakenTempInit,
new BoundTryStatement(
lockSyntax,
BoundBlock.SynthesizedNoLocals(lockSyntax, ImmutableArray.Create(
enterCall,
rewrittenBody)),
ImmutableArray<BoundCatchBlock>.Empty,
BoundBlock.SynthesizedNoLocals(lockSyntax,
exitCall))));
}
else
{
// Pre-4.0 version
// L $lock = `argument`; // sequence point
// Monitor.Enter($lock); // NB: before try-finally so we don't Exit if an exception prevents us from acquiring the lock.
// try
// {
// `body` // sequence point
// }
// finally
// {
// Monitor.Exit($lock); // hidden sequence point
// }
BoundExpression enterCallExpr;
if ((object)enterMethod != null)
{
Debug.Assert(enterMethod.ParameterCount == 1);
enterCallExpr = BoundCall.Synthesized(
lockSyntax,
null,
enterMethod,
boundLockTemp);
}
else
{
enterCallExpr = new BoundBadExpression(lockSyntax, LookupResultKind.NotInvocable, ImmutableArray<Symbol>.Empty, ImmutableArray.Create<BoundExpression>(boundLockTemp), ErrorTypeSymbol.UnknownResultType);
}
BoundStatement enterCall = new BoundExpressionStatement(
lockSyntax,
enterCallExpr);
return new BoundBlock(
lockSyntax,
ImmutableArray.Create(boundLockTemp.LocalSymbol),
ImmutableArray.Create(
InstrumentLockTargetCapture(node, boundLockTempInit),
enterCall,
new BoundTryStatement(
lockSyntax,
BoundBlock.SynthesizedNoLocals(lockSyntax, rewrittenBody),
ImmutableArray<BoundCatchBlock>.Empty,
BoundBlock.SynthesizedNoLocals(lockSyntax, exitCall))));
}
}
private BoundStatement InstrumentLockTargetCapture(BoundLockStatement original, BoundStatement lockTargetCapture)
{
return this.Instrument ?
_instrumenter.InstrumentLockTargetCapture(original, lockTargetCapture) :
lockTargetCapture;
}
}
}