提交 bf8d2ec7 编写于 作者: V Vladimir Sadov 提交者: GitHub

Merge pull request #14959 from VSadov/cacheThis

Introduce local caching of "this" in async methods
......@@ -871,17 +871,28 @@ private void EmitFieldLoad(BoundFieldAccess fieldAccess, bool used)
{
var field = fieldAccess.FieldSymbol;
//TODO: For static field access this may require ..ctor to run. Is this a side-effect?
// Accessing unused instance field on a struct is a noop. Just emit the receiver.
if (!used && !field.IsVolatile && !field.IsStatic && fieldAccess.ReceiverOpt.Type.IsVerifierValue())
if (!used)
{
EmitExpression(fieldAccess.ReceiverOpt, used: false);
return;
// fetching unused captured frame is a no-op (like reading "this")
if (field.IsCapturedFrame)
{
return;
}
// Accessing a volatile field is sideeffecting because it establishes an acquire fence.
// Otherwise, accessing an unused instance field on a struct is a noop. Just emit an unused receiver.
if (!field.IsVolatile && !field.IsStatic && fieldAccess.ReceiverOpt.Type.IsVerifierValue())
{
EmitExpression(fieldAccess.ReceiverOpt, used: false);
return;
}
}
Debug.Assert(!field.IsConst || field.ContainingType.SpecialType == SpecialType.System_Decimal,
"rewriter should lower constant fields into constant expressions");
// static field access is sideeffecting since it gurantees that ..ctor has run.
// we emit static accesses even if unused.
if (field.IsStatic)
{
if (field.IsVolatile)
......@@ -1252,8 +1263,8 @@ private bool CanUseCallOnRefTypeReceiver(BoundExpression receiver)
return true;
case BoundKind.ObjectCreationExpression:
//NOTE: there are cases involving ProxyAttribute
//where newobj may produce null
// NOTE: there are cases involving ProxyAttribute
// where newobj may produce null
return true;
case BoundKind.Conversion:
......@@ -1262,8 +1273,8 @@ private bool CanUseCallOnRefTypeReceiver(BoundExpression receiver)
switch (conversion.ConversionKind)
{
case ConversionKind.Boxing:
//NOTE: boxing can produce null for Nullable, but any call through that
//will result in null reference exceptions anyways.
// NOTE: boxing can produce null for Nullable, but any call through that
// will result in null reference exceptions anyways.
return true;
case ConversionKind.MethodGroup:
......@@ -1277,10 +1288,20 @@ private bool CanUseCallOnRefTypeReceiver(BoundExpression receiver)
break;
case BoundKind.ThisReference:
//NOTE: these actually can be null if called from a different language
//if that has already happen, we will just propagate the behavior.
// NOTE: these actually can be null if called from a different language
// however, we assume it is responsibility of the caller to nullcheck "this"
// if we already have access to "this", we must be in a member and should
// not redo the check
return true;
case BoundKind.FieldAccess:
// same reason as for "ThisReference"
return ((BoundFieldAccess)receiver).FieldSymbol.IsCapturedFrame;
case BoundKind.Local:
// same reason as for "ThisReference"
return ((BoundLocal)receiver).LocalSymbol.SynthesizedKind == SynthesizedLocalKind.FrameCache;
case BoundKind.DelegateCreationExpression:
return true;
......@@ -1295,9 +1316,6 @@ private bool CanUseCallOnRefTypeReceiver(BoundExpression receiver)
case BoundKind.TypeOfOperator:
return true;
case BoundKind.FieldAccess:
return ((BoundFieldAccess)receiver).FieldSymbol.IsCapturedFrame;
case BoundKind.ConditionalReceiver:
return true;
......
......@@ -125,6 +125,7 @@ internal void GenerateMoveNext(BoundStatement body, MethodSymbol moveNextMethod)
bodyBuilder.Add(F.HiddenSequencePoint());
bodyBuilder.Add(F.Assignment(F.Local(cachedState), F.Field(F.This(), stateField)));
bodyBuilder.Add(CacheThisIfNeeded());
var exceptionLocal = F.SynthesizedLocal(F.WellKnownType(WellKnownType.System_Exception));
bodyBuilder.Add(
......@@ -194,6 +195,11 @@ internal void GenerateMoveNext(BoundStatement body, MethodSymbol moveNextMethod)
var locals = ArrayBuilder<LocalSymbol>.GetInstance();
locals.Add(cachedState);
if ((object)cachedThis != null)
{
locals.Add(cachedThis);
}
if ((object)_exprRetValue != null) locals.Add(_exprRetValue);
var newBody =
......@@ -242,7 +248,7 @@ public override BoundNode VisitExpressionStatement(BoundExpressionStatement node
}
BoundExpression expr = (BoundExpression)this.Visit(node.Expression);
return (expr != null) ? node.Update(expr) : (BoundStatement)F.Block();
return (expr != null) ? node.Update(expr) : (BoundStatement)F.StatementList();
}
public override BoundNode VisitAwaitExpression(BoundAwaitExpression node)
......
......@@ -94,12 +94,15 @@ internal void GenerateMoveNextAndDispose(BoundStatement body, SynthesizedImpleme
// }
// state_0:
// state = -1;
// [optional: cachedThis = capturedThis;]
// [[rewritten body]]
newBody = F.Block(ImmutableArray.Create(cachedState),
F.Block(
F.HiddenSequencePoint(),
F.Assignment(F.Local(cachedState), F.Field(F.This(), stateField))
),
newBody = F.Block((object)cachedThis == null?
ImmutableArray.Create(cachedState):
ImmutableArray.Create(cachedState, cachedThis),
F.HiddenSequencePoint(),
F.Assignment(F.Local(cachedState), F.Field(F.This(), stateField)),
CacheThisIfNeeded(),
Dispatch(),
GenerateReturn(finished: true),
F.Label(initialLabel),
......@@ -386,8 +389,11 @@ public override BoundNode VisitTryStatement(BoundTryStatement node)
// return;
// }
Debug.Assert(frame.parent.finalizeState == _currentFinallyFrame.finalizeState);
rewrittenHandler = F.Block(
rewrittenHandler = F.Block((object)this.cachedThis != null?
ImmutableArray.Create(this.cachedThis):
ImmutableArray<LocalSymbol>.Empty,
F.Assignment(F.Field(F.This(), stateField), F.Literal(frame.parent.finalizeState)),
CacheThisIfNeeded(),
rewrittenHandler,
F.Return()
);
......
......@@ -310,7 +310,7 @@ private void GenerateEnumerableImplementation(ref BoundExpression managedThreadI
F.Assignment(F.Local(resultVariable), F.This()), // result = this;
method.IsStatic || method.ThisParameter.Type.IsReferenceType ? // if this is a reference type, no need to copy it since it is not assignable
F.Goto(thisInitialized) : // goto thisInitialized
(BoundStatement)F.Block()),
(BoundStatement)F.StatementList()),
elseClauseOpt:
makeIterator // else result = new IteratorClass(0)
);
......
......@@ -44,6 +44,20 @@ internal abstract class MethodToStateMachineRewriter : MethodToClassRewriter
/// </summary>
protected readonly LocalSymbol cachedState;
/// <summary>
/// Cached "this" local, used to store the captured "this", which is safe to cache locally since "this"
/// is sematically immutable.
/// It would be hard for such caching to happen at JIT level (since JIT does not know that it never changes).
/// NOTE: this field is null when we are not caching "this" which happens when
/// - not optimizing
/// - method is not capturing "this" at all
/// - containing type is a struct
/// (we could cache "this" as a ref local for struct containers,
/// but such caching would not save as much indirection and could actually
/// be done at JIT level, possibly more efficiently)
/// </summary>
protected readonly LocalSymbol cachedThis;
private int _nextState;
/// <summary>
......@@ -136,6 +150,18 @@ internal abstract class MethodToStateMachineRewriter : MethodToClassRewriter
{
this.proxies.Add(proxy.Key, proxy.Value);
}
// create cache local for reference type "this" in Release
var thisParameter = originalMethod.ThisParameter;
CapturedSymbolReplacement thisProxy;
if ((object)thisParameter != null &&
thisParameter.Type.IsReferenceType &&
proxies.TryGetValue(thisParameter, out thisProxy) &&
F.Compilation.Options.OptimizationLevel == OptimizationLevel.Release)
{
BoundExpression thisProxyReplacement = thisProxy.Replacement(F.Syntax, frameType => F.This());
this.cachedThis = F.SynthesizedLocal(thisProxyReplacement.Type, syntax: F.Syntax, kind: SynthesizedLocalKind.FrameCache);
}
}
protected override bool NeedsProxy(Symbol localOrParameter)
......@@ -739,8 +765,28 @@ public override BoundNode VisitTryStatement(BoundTryStatement node)
return result;
}
public override BoundNode VisitThisReference(BoundThisReference node)
protected BoundStatement CacheThisIfNeeded()
{
// restore "this" cache, if there is a cache
if ((object)this.cachedThis != null)
{
CapturedSymbolReplacement proxy = proxies[this.OriginalMethod.ThisParameter];
var fetchThis = proxy.Replacement(F.Syntax, frameType => F.This());
return F.Assignment(F.Local(this.cachedThis), fetchThis);
}
// do nothing
return F.StatementList();
}
public sealed override BoundNode VisitThisReference(BoundThisReference node)
{
// if "this" is cached, return it.
if ((object)this.cachedThis != null)
{
return F.Local(this.cachedThis);
}
var thisParameter = this.OriginalMethod.ThisParameter;
CapturedSymbolReplacement proxy;
if ((object)thisParameter == null || !proxies.TryGetValue(thisParameter, out proxy))
......@@ -768,6 +814,13 @@ public override BoundNode VisitThisReference(BoundThisReference node)
public override BoundNode VisitBaseReference(BoundBaseReference node)
{
// TODO: fix up the type of the resulting node to be the base type
// if "this" is cached, return it.
if ((object)this.cachedThis != null)
{
return F.Local(this.cachedThis);
}
CapturedSymbolReplacement proxy = proxies[this.OriginalMethod.ThisParameter];
Debug.Assert(proxy != null);
return proxy.Replacement(F.Syntax, frameType => F.This());
......
......@@ -14,6 +14,7 @@ namespace Microsoft.CodeAnalysis.CSharp
internal sealed class StateMachineFieldSymbol : SynthesizedFieldSymbolBase, ISynthesizedMethodBodyImplementationSymbol
{
private readonly TypeSymbol _type;
private readonly bool _isThis;
// -1 if the field doesn't represent a long-lived local or an awaiter.
internal readonly int SlotIndex;
......@@ -21,9 +22,10 @@ internal sealed class StateMachineFieldSymbol : SynthesizedFieldSymbolBase, ISyn
internal readonly LocalSlotDebugInfo SlotDebugInfo;
// Some fields need to be public since they are initialized directly by the kickoff method.
public StateMachineFieldSymbol(NamedTypeSymbol stateMachineType, TypeSymbol type, string name, bool isPublic)
public StateMachineFieldSymbol(NamedTypeSymbol stateMachineType, TypeSymbol type, string name, bool isPublic, bool isThis)
: this(stateMachineType, type, name, new LocalSlotDebugInfo(SynthesizedLocalKind.LoweringTemp, LocalDebugId.None), slotIndex: -1, isPublic: isPublic)
{
_isThis = isThis;
}
public StateMachineFieldSymbol(NamedTypeSymbol stateMachineType, TypeSymbol type, string name, SynthesizedLocalKind synthesizedKind, int slotIndex, bool isPublic)
......@@ -61,5 +63,10 @@ IMethodSymbol ISynthesizedMethodBodyImplementationSymbol.Method
{
get { return ((ISynthesizedMethodBodyImplementationSymbol)ContainingSymbol).Method; }
}
internal override bool IsCapturedFrame
{
get { return _isThis; }
}
}
}
......@@ -208,13 +208,13 @@ protected BoundStatement Rewrite()
if (parameter.IsThis)
{
var containingType = method.ContainingType;
var proxyField = F.StateMachineField(containingType, GeneratedNames.ThisProxyFieldName(), isPublic: true);
var proxyField = F.StateMachineField(containingType, GeneratedNames.ThisProxyFieldName(), isPublic: true, isThis: true);
proxiesBuilder.Add(parameter, new CapturedToStateMachineFieldReplacement(proxyField, isReusable: false));
if (PreserveInitialParameterValues)
{
var initialThis = containingType.IsStructType() ?
F.StateMachineField(containingType, GeneratedNames.StateMachineThisParameterProxyName(), isPublic: true) : proxyField;
F.StateMachineField(containingType, GeneratedNames.StateMachineThisParameterProxyName(), isPublic: true, isThis: true) : proxyField;
initialParameters.Add(parameter, new CapturedToStateMachineFieldReplacement(initialThis, isReusable: false));
}
......
......@@ -205,9 +205,9 @@ public BoundHoistedFieldAccess HoistedField(FieldSymbol field)
return new BoundHoistedFieldAccess(Syntax, field, field.Type);
}
public StateMachineFieldSymbol StateMachineField(TypeSymbol type, string name, bool isPublic = false)
public StateMachineFieldSymbol StateMachineField(TypeSymbol type, string name, bool isPublic = false, bool isThis = false)
{
var result = new StateMachineFieldSymbol(CurrentType, type, name, isPublic);
var result = new StateMachineFieldSymbol(CurrentType, type, name, isPublic, isThis);
AddField(CurrentType, result);
return result;
}
......@@ -423,6 +423,11 @@ public BoundBlock Block(ImmutableArray<LocalSymbol> locals, ImmutableArray<Local
return new BoundBlock(Syntax, locals, localFunctions, statements) { WasCompilerGenerated = true };
}
public BoundStatementList StatementList()
{
return StatementList(ImmutableArray<BoundStatement>.Empty);
}
public BoundStatementList StatementList(ImmutableArray<BoundStatement> statements)
{
return new BoundStatementList(Syntax, statements) { WasCompilerGenerated = true };
......
......@@ -1149,7 +1149,102 @@ public IEnumerable Foo()
}
";
// Native print "++ ++ EX 2"
CompileAndVerify(source, expectedOutput: " ++ EX 1");
var verifier = CompileAndVerify(source, expectedOutput: " ++ EX 1");
// must not load "<>4__this"
verifier.VerifyIL("Program.test.<Foo>d__1.System.Collections.IEnumerator.MoveNext()", @"
{
// Code size 101 (0x65)
.maxstack 2
.locals init (bool V_0,
int V_1)
.try
{
IL_0000: ldarg.0
IL_0001: ldfld ""int Program.test.<Foo>d__1.<>1__state""
IL_0006: stloc.1
IL_0007: ldloc.1
IL_0008: brfalse.s IL_0012
IL_000a: ldloc.1
IL_000b: ldc.i4.1
IL_000c: beq.s IL_0033
IL_000e: ldc.i4.0
IL_000f: stloc.0
IL_0010: leave.s IL_0063
IL_0012: ldarg.0
IL_0013: ldc.i4.m1
IL_0014: stfld ""int Program.test.<Foo>d__1.<>1__state""
IL_0019: ldarg.0
IL_001a: ldc.i4.s -3
IL_001c: stfld ""int Program.test.<Foo>d__1.<>1__state""
IL_0021: ldarg.0
IL_0022: ldnull
IL_0023: stfld ""object Program.test.<Foo>d__1.<>2__current""
IL_0028: ldarg.0
IL_0029: ldc.i4.1
IL_002a: stfld ""int Program.test.<Foo>d__1.<>1__state""
IL_002f: ldc.i4.1
IL_0030: stloc.0
IL_0031: leave.s IL_0063
IL_0033: ldarg.0
IL_0034: ldc.i4.s -3
IL_0036: stfld ""int Program.test.<Foo>d__1.<>1__state""
.try
{
IL_003b: ldc.i4.0
IL_003c: stloc.0
IL_003d: leave.s IL_004a
}
catch object
{
IL_003f: pop
IL_0040: leave.s IL_0042
}
IL_0042: ldarg.0
IL_0043: call ""void Program.test.<Foo>d__1.<>m__Finally1()""
IL_0048: br.s IL_0052
IL_004a: ldarg.0
IL_004b: call ""void Program.test.<Foo>d__1.<>m__Finally1()""
IL_0050: leave.s IL_0063
IL_0052: leave.s IL_005b
}
fault
{
IL_0054: ldarg.0
IL_0055: call ""void Program.test.<Foo>d__1.Dispose()""
IL_005a: endfinally
}
IL_005b: ldarg.0
IL_005c: call ""void Program.test.<Foo>d__1.Dispose()""
IL_0061: ldc.i4.1
IL_0062: stloc.0
IL_0063: ldloc.0
IL_0064: ret
}
");
// must load "<>4__this"
verifier.VerifyIL("Program.test.<Foo>d__1.<>m__Finally1()", @"
{
// Code size 42 (0x2a)
.maxstack 3
IL_0000: ldarg.0
IL_0001: ldc.i4.m1
IL_0002: stfld ""int Program.test.<Foo>d__1.<>1__state""
IL_0007: ldarg.0
IL_0008: ldfld ""Program.test Program.test.<Foo>d__1.<>4__this""
IL_000d: ldstr ""++ ""
IL_0012: call ""void System.Console.Write(string)""
IL_0017: dup
IL_0018: ldfld ""int Program.test.count""
IL_001d: ldc.i4.1
IL_001e: add
IL_001f: stfld ""int Program.test.count""
IL_0024: newobj ""System.Exception..ctor()""
IL_0029: throw
}
");
}
[Fact, WorkItem(530587, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/530587")]
......
......@@ -499,7 +499,397 @@ public static void Main()
var expected = @"
42
";
CompileAndVerify(source, expectedOutput: expected);
var verifier = CompileAndVerify(source, expectedOutput: expected);
verifier.VerifyIL("C.<F>d__1.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext()", @"
{
// Code size 199 (0xc7)
.maxstack 3
.locals init (int V_0,
C V_1,
int V_2,
C.<>c__DisplayClass1_0 V_3, //CS$<>8__locals0
System.Runtime.CompilerServices.TaskAwaiter<int> V_4,
System.Exception V_5)
IL_0000: ldarg.0
IL_0001: ldfld ""int C.<F>d__1.<>1__state""
IL_0006: stloc.0
IL_0007: ldarg.0
IL_0008: ldfld ""C C.<F>d__1.<>4__this""
IL_000d: stloc.1
.try
{
IL_000e: ldloc.0
IL_000f: brfalse.s IL_006a
IL_0011: newobj ""C.<>c__DisplayClass1_0..ctor()""
IL_0016: stloc.3
IL_0017: ldloc.3
IL_0018: ldloc.1
IL_0019: ldfld ""int C.x""
IL_001e: stfld ""int C.<>c__DisplayClass1_0.c""
IL_0023: call ""System.Threading.Tasks.TaskFactory System.Threading.Tasks.Task.Factory.get""
IL_0028: ldloc.3
IL_0029: ldftn ""int C.<>c__DisplayClass1_0.<F>b__0()""
IL_002f: newobj ""System.Func<int>..ctor(object, System.IntPtr)""
IL_0034: callvirt ""System.Threading.Tasks.Task<int> System.Threading.Tasks.TaskFactory.StartNew<int>(System.Func<int>)""
IL_0039: callvirt ""System.Runtime.CompilerServices.TaskAwaiter<int> System.Threading.Tasks.Task<int>.GetAwaiter()""
IL_003e: stloc.s V_4
IL_0040: ldloca.s V_4
IL_0042: call ""bool System.Runtime.CompilerServices.TaskAwaiter<int>.IsCompleted.get""
IL_0047: brtrue.s IL_0087
IL_0049: ldarg.0
IL_004a: ldc.i4.0
IL_004b: dup
IL_004c: stloc.0
IL_004d: stfld ""int C.<F>d__1.<>1__state""
IL_0052: ldarg.0
IL_0053: ldloc.s V_4
IL_0055: stfld ""System.Runtime.CompilerServices.TaskAwaiter<int> C.<F>d__1.<>u__1""
IL_005a: ldarg.0
IL_005b: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder<int> C.<F>d__1.<>t__builder""
IL_0060: ldloca.s V_4
IL_0062: ldarg.0
IL_0063: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder<int>.AwaitUnsafeOnCompleted<System.Runtime.CompilerServices.TaskAwaiter<int>, C.<F>d__1>(ref System.Runtime.CompilerServices.TaskAwaiter<int>, ref C.<F>d__1)""
IL_0068: leave.s IL_00c6
IL_006a: ldarg.0
IL_006b: ldfld ""System.Runtime.CompilerServices.TaskAwaiter<int> C.<F>d__1.<>u__1""
IL_0070: stloc.s V_4
IL_0072: ldarg.0
IL_0073: ldflda ""System.Runtime.CompilerServices.TaskAwaiter<int> C.<F>d__1.<>u__1""
IL_0078: initobj ""System.Runtime.CompilerServices.TaskAwaiter<int>""
IL_007e: ldarg.0
IL_007f: ldc.i4.m1
IL_0080: dup
IL_0081: stloc.0
IL_0082: stfld ""int C.<F>d__1.<>1__state""
IL_0087: ldloca.s V_4
IL_0089: call ""int System.Runtime.CompilerServices.TaskAwaiter<int>.GetResult()""
IL_008e: ldloca.s V_4
IL_0090: initobj ""System.Runtime.CompilerServices.TaskAwaiter<int>""
IL_0096: stloc.2
IL_0097: leave.s IL_00b2
}
catch System.Exception
{
IL_0099: stloc.s V_5
IL_009b: ldarg.0
IL_009c: ldc.i4.s -2
IL_009e: stfld ""int C.<F>d__1.<>1__state""
IL_00a3: ldarg.0
IL_00a4: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder<int> C.<F>d__1.<>t__builder""
IL_00a9: ldloc.s V_5
IL_00ab: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder<int>.SetException(System.Exception)""
IL_00b0: leave.s IL_00c6
}
IL_00b2: ldarg.0
IL_00b3: ldc.i4.s -2
IL_00b5: stfld ""int C.<F>d__1.<>1__state""
IL_00ba: ldarg.0
IL_00bb: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder<int> C.<F>d__1.<>t__builder""
IL_00c0: ldloc.2
IL_00c1: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder<int>.SetResult(int)""
IL_00c6: ret
}
");
}
[Fact]
public void AsyncWithThisRef01()
{
var source = @"
using System;
using System.Threading.Tasks;
class C
{
int x => 14;
public async Task<int> F()
{
int c = this.x;
await Task.Yield();
c += this.x;
await Task.Yield();
c += this.x;
await Task.Yield();
await Task.Yield();
await Task.Yield();
return c;
}
}
class Test
{
public static void Main()
{
Task<int> t = new C().F();
t.Wait(1000 * 60);
Console.WriteLine(t.Result);
}
}";
var expected = @"
42
";
var verifier = CompileAndVerify(source, expectedOutput: expected);
verifier.VerifyIL("C.<F>d__2.System.Runtime.CompilerServices.IAsyncStateMachine.MoveNext()", @"
{
// Code size 652 (0x28c)
.maxstack 3
.locals init (int V_0,
C V_1,
int V_2,
System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter V_3,
System.Runtime.CompilerServices.YieldAwaitable V_4,
System.Exception V_5)
IL_0000: ldarg.0
IL_0001: ldfld ""int C.<F>d__2.<>1__state""
IL_0006: stloc.0
IL_0007: ldarg.0
IL_0008: ldfld ""C C.<F>d__2.<>4__this""
IL_000d: stloc.1
.try
{
IL_000e: ldloc.0
IL_000f: switch (
IL_006f,
IL_00e8,
IL_0161,
IL_01c7,
IL_022a)
IL_0028: ldarg.0
IL_0029: ldloc.1
IL_002a: call ""int C.x.get""
IL_002f: stfld ""int C.<F>d__2.<c>5__1""
IL_0034: call ""System.Runtime.CompilerServices.YieldAwaitable System.Threading.Tasks.Task.Yield()""
IL_0039: stloc.s V_4
IL_003b: ldloca.s V_4
IL_003d: call ""System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter System.Runtime.CompilerServices.YieldAwaitable.GetAwaiter()""
IL_0042: stloc.3
IL_0043: ldloca.s V_3
IL_0045: call ""bool System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter.IsCompleted.get""
IL_004a: brtrue.s IL_008b
IL_004c: ldarg.0
IL_004d: ldc.i4.0
IL_004e: dup
IL_004f: stloc.0
IL_0050: stfld ""int C.<F>d__2.<>1__state""
IL_0055: ldarg.0
IL_0056: ldloc.3
IL_0057: stfld ""System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter C.<F>d__2.<>u__1""
IL_005c: ldarg.0
IL_005d: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder<int> C.<F>d__2.<>t__builder""
IL_0062: ldloca.s V_3
IL_0064: ldarg.0
IL_0065: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder<int>.AwaitUnsafeOnCompleted<System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter, C.<F>d__2>(ref System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter, ref C.<F>d__2)""
IL_006a: leave IL_028b
IL_006f: ldarg.0
IL_0070: ldfld ""System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter C.<F>d__2.<>u__1""
IL_0075: stloc.3
IL_0076: ldarg.0
IL_0077: ldflda ""System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter C.<F>d__2.<>u__1""
IL_007c: initobj ""System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter""
IL_0082: ldarg.0
IL_0083: ldc.i4.m1
IL_0084: dup
IL_0085: stloc.0
IL_0086: stfld ""int C.<F>d__2.<>1__state""
IL_008b: ldloca.s V_3
IL_008d: call ""void System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter.GetResult()""
IL_0092: ldloca.s V_3
IL_0094: initobj ""System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter""
IL_009a: ldarg.0
IL_009b: ldarg.0
IL_009c: ldfld ""int C.<F>d__2.<c>5__1""
IL_00a1: ldloc.1
IL_00a2: call ""int C.x.get""
IL_00a7: add
IL_00a8: stfld ""int C.<F>d__2.<c>5__1""
IL_00ad: call ""System.Runtime.CompilerServices.YieldAwaitable System.Threading.Tasks.Task.Yield()""
IL_00b2: stloc.s V_4
IL_00b4: ldloca.s V_4
IL_00b6: call ""System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter System.Runtime.CompilerServices.YieldAwaitable.GetAwaiter()""
IL_00bb: stloc.3
IL_00bc: ldloca.s V_3
IL_00be: call ""bool System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter.IsCompleted.get""
IL_00c3: brtrue.s IL_0104
IL_00c5: ldarg.0
IL_00c6: ldc.i4.1
IL_00c7: dup
IL_00c8: stloc.0
IL_00c9: stfld ""int C.<F>d__2.<>1__state""
IL_00ce: ldarg.0
IL_00cf: ldloc.3
IL_00d0: stfld ""System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter C.<F>d__2.<>u__1""
IL_00d5: ldarg.0
IL_00d6: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder<int> C.<F>d__2.<>t__builder""
IL_00db: ldloca.s V_3
IL_00dd: ldarg.0
IL_00de: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder<int>.AwaitUnsafeOnCompleted<System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter, C.<F>d__2>(ref System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter, ref C.<F>d__2)""
IL_00e3: leave IL_028b
IL_00e8: ldarg.0
IL_00e9: ldfld ""System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter C.<F>d__2.<>u__1""
IL_00ee: stloc.3
IL_00ef: ldarg.0
IL_00f0: ldflda ""System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter C.<F>d__2.<>u__1""
IL_00f5: initobj ""System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter""
IL_00fb: ldarg.0
IL_00fc: ldc.i4.m1
IL_00fd: dup
IL_00fe: stloc.0
IL_00ff: stfld ""int C.<F>d__2.<>1__state""
IL_0104: ldloca.s V_3
IL_0106: call ""void System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter.GetResult()""
IL_010b: ldloca.s V_3
IL_010d: initobj ""System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter""
IL_0113: ldarg.0
IL_0114: ldarg.0
IL_0115: ldfld ""int C.<F>d__2.<c>5__1""
IL_011a: ldloc.1
IL_011b: call ""int C.x.get""
IL_0120: add
IL_0121: stfld ""int C.<F>d__2.<c>5__1""
IL_0126: call ""System.Runtime.CompilerServices.YieldAwaitable System.Threading.Tasks.Task.Yield()""
IL_012b: stloc.s V_4
IL_012d: ldloca.s V_4
IL_012f: call ""System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter System.Runtime.CompilerServices.YieldAwaitable.GetAwaiter()""
IL_0134: stloc.3
IL_0135: ldloca.s V_3
IL_0137: call ""bool System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter.IsCompleted.get""
IL_013c: brtrue.s IL_017d
IL_013e: ldarg.0
IL_013f: ldc.i4.2
IL_0140: dup
IL_0141: stloc.0
IL_0142: stfld ""int C.<F>d__2.<>1__state""
IL_0147: ldarg.0
IL_0148: ldloc.3
IL_0149: stfld ""System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter C.<F>d__2.<>u__1""
IL_014e: ldarg.0
IL_014f: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder<int> C.<F>d__2.<>t__builder""
IL_0154: ldloca.s V_3
IL_0156: ldarg.0
IL_0157: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder<int>.AwaitUnsafeOnCompleted<System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter, C.<F>d__2>(ref System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter, ref C.<F>d__2)""
IL_015c: leave IL_028b
IL_0161: ldarg.0
IL_0162: ldfld ""System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter C.<F>d__2.<>u__1""
IL_0167: stloc.3
IL_0168: ldarg.0
IL_0169: ldflda ""System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter C.<F>d__2.<>u__1""
IL_016e: initobj ""System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter""
IL_0174: ldarg.0
IL_0175: ldc.i4.m1
IL_0176: dup
IL_0177: stloc.0
IL_0178: stfld ""int C.<F>d__2.<>1__state""
IL_017d: ldloca.s V_3
IL_017f: call ""void System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter.GetResult()""
IL_0184: ldloca.s V_3
IL_0186: initobj ""System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter""
IL_018c: call ""System.Runtime.CompilerServices.YieldAwaitable System.Threading.Tasks.Task.Yield()""
IL_0191: stloc.s V_4
IL_0193: ldloca.s V_4
IL_0195: call ""System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter System.Runtime.CompilerServices.YieldAwaitable.GetAwaiter()""
IL_019a: stloc.3
IL_019b: ldloca.s V_3
IL_019d: call ""bool System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter.IsCompleted.get""
IL_01a2: brtrue.s IL_01e3
IL_01a4: ldarg.0
IL_01a5: ldc.i4.3
IL_01a6: dup
IL_01a7: stloc.0
IL_01a8: stfld ""int C.<F>d__2.<>1__state""
IL_01ad: ldarg.0
IL_01ae: ldloc.3
IL_01af: stfld ""System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter C.<F>d__2.<>u__1""
IL_01b4: ldarg.0
IL_01b5: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder<int> C.<F>d__2.<>t__builder""
IL_01ba: ldloca.s V_3
IL_01bc: ldarg.0
IL_01bd: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder<int>.AwaitUnsafeOnCompleted<System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter, C.<F>d__2>(ref System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter, ref C.<F>d__2)""
IL_01c2: leave IL_028b
IL_01c7: ldarg.0
IL_01c8: ldfld ""System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter C.<F>d__2.<>u__1""
IL_01cd: stloc.3
IL_01ce: ldarg.0
IL_01cf: ldflda ""System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter C.<F>d__2.<>u__1""
IL_01d4: initobj ""System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter""
IL_01da: ldarg.0
IL_01db: ldc.i4.m1
IL_01dc: dup
IL_01dd: stloc.0
IL_01de: stfld ""int C.<F>d__2.<>1__state""
IL_01e3: ldloca.s V_3
IL_01e5: call ""void System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter.GetResult()""
IL_01ea: ldloca.s V_3
IL_01ec: initobj ""System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter""
IL_01f2: call ""System.Runtime.CompilerServices.YieldAwaitable System.Threading.Tasks.Task.Yield()""
IL_01f7: stloc.s V_4
IL_01f9: ldloca.s V_4
IL_01fb: call ""System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter System.Runtime.CompilerServices.YieldAwaitable.GetAwaiter()""
IL_0200: stloc.3
IL_0201: ldloca.s V_3
IL_0203: call ""bool System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter.IsCompleted.get""
IL_0208: brtrue.s IL_0246
IL_020a: ldarg.0
IL_020b: ldc.i4.4
IL_020c: dup
IL_020d: stloc.0
IL_020e: stfld ""int C.<F>d__2.<>1__state""
IL_0213: ldarg.0
IL_0214: ldloc.3
IL_0215: stfld ""System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter C.<F>d__2.<>u__1""
IL_021a: ldarg.0
IL_021b: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder<int> C.<F>d__2.<>t__builder""
IL_0220: ldloca.s V_3
IL_0222: ldarg.0
IL_0223: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder<int>.AwaitUnsafeOnCompleted<System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter, C.<F>d__2>(ref System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter, ref C.<F>d__2)""
IL_0228: leave.s IL_028b
IL_022a: ldarg.0
IL_022b: ldfld ""System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter C.<F>d__2.<>u__1""
IL_0230: stloc.3
IL_0231: ldarg.0
IL_0232: ldflda ""System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter C.<F>d__2.<>u__1""
IL_0237: initobj ""System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter""
IL_023d: ldarg.0
IL_023e: ldc.i4.m1
IL_023f: dup
IL_0240: stloc.0
IL_0241: stfld ""int C.<F>d__2.<>1__state""
IL_0246: ldloca.s V_3
IL_0248: call ""void System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter.GetResult()""
IL_024d: ldloca.s V_3
IL_024f: initobj ""System.Runtime.CompilerServices.YieldAwaitable.YieldAwaiter""
IL_0255: ldarg.0
IL_0256: ldfld ""int C.<F>d__2.<c>5__1""
IL_025b: stloc.2
IL_025c: leave.s IL_0277
}
catch System.Exception
{
IL_025e: stloc.s V_5
IL_0260: ldarg.0
IL_0261: ldc.i4.s -2
IL_0263: stfld ""int C.<F>d__2.<>1__state""
IL_0268: ldarg.0
IL_0269: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder<int> C.<F>d__2.<>t__builder""
IL_026e: ldloc.s V_5
IL_0270: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder<int>.SetException(System.Exception)""
IL_0275: leave.s IL_028b
}
IL_0277: ldarg.0
IL_0278: ldc.i4.s -2
IL_027a: stfld ""int C.<F>d__2.<>1__state""
IL_027f: ldarg.0
IL_0280: ldflda ""System.Runtime.CompilerServices.AsyncTaskMethodBuilder<int> C.<F>d__2.<>t__builder""
IL_0285: ldloc.2
IL_0286: call ""void System.Runtime.CompilerServices.AsyncTaskMethodBuilder<int>.SetResult(int)""
IL_028b: ret
}
");
}
[Fact]
......
......@@ -3970,7 +3970,7 @@ .maxstack 4
IL_000d: ldarg.0
IL_000e: ldfld ""Script <<Initialize>>d__0.<>4__this""
IL_0013: ldflda ""int x1""
IL_0018: callvirt ""(int, int) M(out int)""
IL_0018: call ""(int, int) M(out int)""
IL_001d: dup
IL_001e: ldfld ""int System.ValueTuple<int, int>.Item1""
IL_0023: stloc.2
......
......@@ -2884,7 +2884,7 @@ .locals init (int V_0)
IL_0020: ldarg.0
IL_0021: ldarg.0
IL_0022: ldfld ""C C.<F>d__0.<>4__this""
IL_0027: callvirt ""System.Collections.Generic.IEnumerable<int> C.F()""
IL_0027: call ""System.Collections.Generic.IEnumerable<int> C.F()""
IL_002c: stfld ""System.Collections.Generic.IEnumerable<int> C.<F>d__0.<>s__1""
IL_0031: ldarg.0
IL_0032: ldc.i4.0
......@@ -2989,7 +2989,7 @@ .maxstack 3
-IL_0012: ldarg.0
IL_0013: ldarg.0
IL_0014: ldfld ""C C.<F>d__0.<>4__this""
IL_0019: callvirt ""System.Threading.Tasks.Task<int> C.F()""
IL_0019: call ""System.Threading.Tasks.Task<int> C.F()""
IL_001e: stfld ""System.Threading.Tasks.Task<int> C.<F>d__0.<>s__1""
IL_0023: ldarg.0
IL_0024: ldc.i4.0
......@@ -3025,7 +3025,7 @@ .maxstack 3
IL_005b: stfld ""System.Threading.Tasks.Task<int> C.<F>d__0.<>s__1""
-IL_0060: ldarg.0
IL_0061: ldfld ""C C.<F>d__0.<>4__this""
IL_0066: callvirt ""System.Threading.Tasks.Task<int> C.F()""
IL_0066: call ""System.Threading.Tasks.Task<int> C.F()""
IL_006b: callvirt ""System.Runtime.CompilerServices.TaskAwaiter<int> System.Threading.Tasks.Task<int>.GetAwaiter()""
IL_0070: stloc.2
~IL_0071: ldloca.s V_2
......
......@@ -26,6 +26,12 @@ namespace Microsoft.CodeAnalysis
/// </remarks>
internal enum SynthesizedLocalKind
{
/// <summary>
/// Temp created for caching "this".
/// Technically it is long-lived, but will happen only in optimized code.
/// </summary>
FrameCache = -5,
/// <summary>
/// Temp created for pattern matching by type.
/// </summary>
......
......@@ -73,7 +73,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
builder.AddStatement(
Me.F.If(
condition:=Me.F.Convert(Me.F.SpecialType(SpecialType.System_Boolean), rewrittenIsCompleted),
thenClause:=Me.F.Block(),
thenClause:=Me.F.StatementList(),
elseClause:=awaitForIncompleteTask))
Else
' regular case
......
......@@ -108,7 +108,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Private Function HandleReturn() As BoundStatement
If Me._exitLabel Is Nothing Then
' did not see indirect returns
Return F.Block()
Return F.StatementList()
Else
' _methodValue = False
' exitlabel:
......
......@@ -216,7 +216,7 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
F.Assignment(F.Local(resultVariable, True), F.Me),
If(Method.IsShared OrElse Method.MeParameter.Type.IsReferenceType,
F.Goto(thisInitialized),
DirectCast(F.Block(), BoundStatement))
DirectCast(F.StatementList(), BoundStatement))
),
elseClause:=
F.Assignment(F.Local(resultVariable, True), F.[New](StateMachineType.Constructor, F.Literal(0)))
......
......@@ -357,6 +357,10 @@ Namespace Microsoft.CodeAnalysis.VisualBasic
Return Block(locals, ImmutableArray.Create(Of BoundStatement)(statements))
End Function
Public Function StatementList() As BoundStatementList
Return StatementList(ImmutableArray(Of BoundStatement).Empty)
End Function
Public Function StatementList(statements As ImmutableArray(Of BoundStatement)) As BoundStatementList
Dim boundNode As New BoundStatementList(Syntax, statements)
boundNode.SetWasCompilerGenerated()
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册