return true;
}
+ public override void FlowAnalysis (FlowAnalysisContext fc)
+ {
+ stmt.Expr.FlowAnalysis (fc);
+
+ stmt.RegisterResumePoint ();
+ }
+
protected override Expression DoResolve (ResolveContext rc)
{
if (rc.HasSet (ResolveContext.Options.LockScope)) {
stmt.EmitStatement (ec);
}
+ public override void MarkReachable (Reachability rc)
+ {
+ base.MarkReachable (rc);
+ stmt.MarkReachable (rc);
+ }
+
public override object Accept (StructuralVisitor visitor)
{
return visitor.Visit (this);
public AwaitStatement (Expression expr, Location loc)
: base (expr, loc)
{
+ unwind_protect = true;
}
#region Properties
var fe_awaiter = new FieldExpr (awaiter, loc);
fe_awaiter.InstanceExpression = new CompilerGeneratedThis (ec.CurrentType, loc);
- Label skip_continuation = ec.DefineLabel ();
+ Label skip_continuation = ec.DefineLabel ();
using (ec.With (BuilderContext.Options.OmitDebugInfo, true)) {
//
}
}
+ class AsyncInitializerStatement : StatementExpression
+ {
+ public AsyncInitializerStatement (AsyncInitializer expr)
+ : base (expr)
+ {
+ }
+
+ protected override bool DoFlowAnalysis (FlowAnalysisContext fc)
+ {
+ base.DoFlowAnalysis (fc);
+
+ var init = (AsyncInitializer) Expr;
+ var res = !init.Block.HasReachableClosingBrace;
+ var storey = (AsyncTaskStorey) init.Storey;
+
+ if (storey.ReturnType.IsGenericTask)
+ return res;
+
+ return true;
+ }
+
+ public override Reachability MarkReachable (Reachability rc)
+ {
+ if (!rc.IsUnreachable)
+ reachable = true;
+
+ var init = (AsyncInitializer) Expr;
+ rc = init.Block.MarkReachable (rc);
+
+ var storey = (AsyncTaskStorey) init.Storey;
+
+ //
+ // Explicit return is required for Task<T> state machine
+ //
+ if (storey.ReturnType != null && storey.ReturnType.IsGenericTask)
+ return rc;
+
+ return Reachability.CreateUnreachable ();
+ }
+ }
+
public class AsyncInitializer : StateMachineInitializer
{
TypeInferenceContext return_inference;
get; set;
}
+ public StackFieldExpr HoistedReturnState {
+ get; set;
+ }
+
public override bool IsIterator {
get {
return false;
#endregion
- protected override BlockContext CreateBlockContext (ResolveContext rc)
+ protected override BlockContext CreateBlockContext (BlockContext bc)
{
- var ctx = base.CreateBlockContext (rc);
- var lambda = rc.CurrentAnonymousMethod as LambdaMethod;
- if (lambda != null)
- return_inference = lambda.ReturnTypeInference;
+ var ctx = base.CreateBlockContext (bc);
+ var am = bc.CurrentAnonymousMethod as AnonymousMethodBody;
+ if (am != null)
+ return_inference = am.ReturnTypeInference;
+
+ ctx.Set (ResolveContext.Options.TryScope);
- ctx.StartFlowBranching (this, rc.CurrentBranching);
return ctx;
}
throw new NotImplementedException ();
}
+ public void EmitCatchBlock (EmitContext ec)
+ {
+ var catch_value = LocalVariable.CreateCompilerGenerated (ec.Module.Compiler.BuiltinTypes.Exception, block, Location);
+
+ ec.BeginCatchBlock (catch_value.Type);
+ catch_value.EmitAssign (ec);
+
+ ec.EmitThis ();
+ ec.EmitInt ((int) IteratorStorey.State.After);
+ ec.Emit (OpCodes.Stfld, storey.PC.Spec);
+
+ ((AsyncTaskStorey) Storey).EmitSetException (ec, new LocalVariableReference (catch_value, Location));
+
+ ec.Emit (OpCodes.Leave, move_next_ok);
+ ec.EndExceptionBlock ();
+
+ }
+
protected override void EmitMoveNextEpilogue (EmitContext ec)
{
var storey = (AsyncTaskStorey) Storey;
storey.EmitInitializer (ec);
ec.Emit (OpCodes.Ret);
}
+
+ public override void MarkReachable (Reachability rc)
+ {
+ //
+ // Reachability has been done in AsyncInitializerStatement
+ //
+ }
}
class AsyncTaskStorey : StateMachine
MethodSpec builder_factory;
MethodSpec builder_start;
PropertySpec task;
- LocalVariable hoisted_return;
int locals_captured;
Dictionary<TypeSpec, List<Field>> stack_fields;
Dictionary<TypeSpec, List<Field>> awaiter_fields;
#region Properties
- public LocalVariable HoistedReturn {
- get {
- return hoisted_return;
- }
- }
+ public Expression HoistedReturnValue { get; set; }
public TypeSpec ReturnType {
get {
return field;
}
- public Field AddCapturedLocalVariable (TypeSpec type)
+ public Field AddCapturedLocalVariable (TypeSpec type, bool requiresUninitialized = false)
{
if (mutator != null)
type = mutator.Mutate (type);
List<Field> existing_fields = null;
if (stack_fields == null) {
stack_fields = new Dictionary<TypeSpec, List<Field>> ();
- } else if (stack_fields.TryGetValue (type, out existing_fields)) {
+ } else if (stack_fields.TryGetValue (type, out existing_fields) && !requiresUninitialized) {
foreach (var f in existing_fields) {
if (f.IsAvailableForReuse) {
f.IsAvailableForReuse = false;
set_state_machine.Block.AddStatement (new StatementExpression (new Invocation (mg, args)));
if (has_task_return_type) {
- hoisted_return = LocalVariable.CreateCompilerGenerated (bt.TypeArguments[0], StateMachineMethod.Block, Location);
+ HoistedReturnValue = TemporaryVariableReference.Create (bt.TypeArguments [0], StateMachineMethod.Block, Location);
}
return true;
args.Add (new Argument (awaiter, Argument.AType.Ref));
args.Add (new Argument (new CompilerGeneratedThis (CurrentType, Location), Argument.AType.Ref));
using (ec.With (BuilderContext.Options.OmitDebugInfo, true)) {
- mg.EmitCall (ec, args);
+ mg.EmitCall (ec, args, true);
}
}
args.Add (new Argument (exceptionVariable));
using (ec.With (BuilderContext.Options.OmitDebugInfo, true)) {
- mg.EmitCall (ec, args);
+ mg.EmitCall (ec, args, true);
}
}
};
Arguments args;
- if (hoisted_return == null) {
+ if (HoistedReturnValue == null) {
args = new Arguments (0);
} else {
args = new Arguments (1);
- args.Add (new Argument (new LocalVariableReference (hoisted_return, Location)));
+ args.Add (new Argument (HoistedReturnValue));
}
using (ec.With (BuilderContext.Options.OmitDebugInfo, true)) {
- mg.EmitCall (ec, args);
+ mg.EmitCall (ec, args, true);
}
}
}
}
- class StackFieldExpr : FieldExpr, IExpressionCleanup
+ public class StackFieldExpr : FieldExpr, IExpressionCleanup
{
public StackFieldExpr (Field field)
: base (field, Location.Null)
{
}
+ public bool IsAvailableForReuse {
+ get {
+ var field = (Field) spec.MemberDefinition;
+ return field.IsAvailableForReuse;
+ }
+ set {
+ var field = (Field) spec.MemberDefinition;
+ field.IsAvailableForReuse = value;
+ }
+ }
+
public override void AddressOf (EmitContext ec, AddressOp mode)
{
base.AddressOf (ec, mode);
if (mode == AddressOp.Load) {
- var field = (Field) spec.MemberDefinition;
- field.IsAvailableForReuse = true;
+ IsAvailableForReuse = true;
}
}
{
base.Emit (ec);
- var field = (Field) spec.MemberDefinition;
- field.IsAvailableForReuse = true;
+ PrepareCleanup (ec);
+ }
+
+ public void EmitLoad (EmitContext ec)
+ {
+ base.Emit (ec);
+ }
+
+ public void PrepareCleanup (EmitContext ec)
+ {
+ IsAvailableForReuse = true;
//
// Release any captured reference type stack variables