// Author:
// Miguel de Icaza (miguel@ximian.com)
//
-// (C) 2003 Ximian, Inc.
+// Copyright 2003 Ximian, Inc.
//
// TODO:
// Flow analysis for Yield.
namespace Mono.CSharp {
- public class Yield : Statement {
+ public class Yield : ResumableStatement {
Expression expr;
- ArrayList finally_blocks;
+ bool unwind_protect;
+
+ int resume_pc;
public Yield (Expression expr, Location l)
{
public static bool CheckContext (EmitContext ec, Location loc, bool isYieldBreak)
{
- if (ec.InFinally) {
- Report.Error (1625, loc, "Cannot yield in the body of a " +
- "finally clause");
- return false;
- }
-
for (Block block = ec.CurrentBlock; block != null; block = block.Parent) {
if (!block.Unsafe)
continue;
return false;
}
- if (ec.CurrentBranching.InTryWithCatch () && (!isYieldBreak || !ec.InCatch)) {
- if (!ec.InCatch)
- Report.Error (1626, loc, "Cannot yield a value in the body " +
- "of a try block with a catch clause");
- else
- Report.Error (1631, loc, "Cannot yield a value in the body " +
- "of a catch clause");
- return false;
- }
-
return true;
}
return false;
}
- ec.CurrentBranching.StealFinallyClauses (ref finally_blocks);
+ unwind_protect = ec.CurrentBranching.AddResumePoint (this, loc, out resume_pc);
+
return true;
}
protected override void DoEmit (EmitContext ec)
{
- ec.CurrentIterator.MarkYield (ec, expr, finally_blocks);
+ ec.CurrentIterator.MarkYield (ec, expr, resume_pc, unwind_protect, resume_point);
}
protected override void CloneTo (CloneContext clonectx, Statement t)
}
}
- public class YieldBreak : Statement {
-
+ public class YieldBreak : ExitStatement {
public YieldBreak (Location l)
{
loc = l;
}
- public override bool Resolve (EmitContext ec)
+ public override void Error_FinallyClause ()
{
- if (!Yield.CheckContext (ec, loc, true))
- return false;
+ Report.Error (1625, loc, "Cannot yield in the body of a finally clause");
+ }
- ec.CurrentBranching.CurrentUsageVector.Goto ();
- return true;
+ protected override bool DoResolve (EmitContext ec)
+ {
+ return Yield.CheckContext (ec, loc, true);
}
protected override void DoEmit (EmitContext ec)
{
- ec.CurrentIterator.EmitYieldBreak (ec.ig);
+ ec.CurrentIterator.EmitYieldBreak (ec.ig, unwind_protect);
}
}
list.Add (generic_enumerator_type);
#endif
- Bases = list;
+ type_bases = list;
return base.GetClassBases (out base_class);
}
void Define_Current (bool is_generic)
{
MemberName left;
- Expression type;
+ TypeExpr type;
if (is_generic) {
left = new MemberName (
Statement Create_ThrowNotSupported ()
{
- TypeExpr ex_type = new TypeExpression (
- TypeManager.not_supported_exception_type, Location);
+ TypeExpr ex_type = new TypeLookupExpression ("System.NotSupportedException");
return new Throw (new New (ex_type, null, Location), Location);
}
- ConstructorInfo GetInvalidOperationException ()
- {
- return TypeManager.GetConstructor (
- TypeManager.invalid_operation_exception_type, Type.EmptyTypes);
- }
-
protected override ScopeInitializer CreateScopeInitializer ()
{
return new IteratorHostInitializer (this);
protected override bool DoResolveInternal (EmitContext ec)
{
if (this is EnumeratorScopeInitializer)
- state = Iterator.State.Running;
+ state = Iterator.State.Start;
else if (Host.Iterator.IsEnumerable)
state = Iterator.State.Uninitialized;
else
- state = Iterator.State.Running;
+ state = Iterator.State.Start;
return base.DoResolveInternal (ec);
}
host.AddMethod (this);
Block = new ToplevelBlock (host.Iterator.Container.Toplevel, null, Location);
- Block.AddStatement (new GetEnumeratorStatement (host, Type));
+ Block.AddStatement (new GetEnumeratorStatement (host, type_name));
}
public override EmitContext CreateEmitContext (DeclSpace tc, ILGenerator ig)
return ec;
}
+ public override void EmitExtraSymbolInfo (SourceMethod source)
+ {
+ source.SetCompilerGenerated ();
+ }
+
protected class GetEnumeratorStatement : Statement
{
IteratorHost host;
cast = new ClassCast (initializer, type.Type);
+ if (TypeManager.int_interlocked_compare_exchange == null) {
+ Type t = TypeManager.CoreLookupType ("System.Threading", "Interlocked", Kind.Class, true);
+ if (t != null) {
+ TypeManager.int_interlocked_compare_exchange = TypeManager.GetPredefinedMethod (
+ t, "CompareExchange", loc, TypeManager.GetReferenceType (TypeManager.int32_type),
+ TypeManager.int32_type, TypeManager.int32_type);
+ }
+ }
+
ce = TypeManager.int_interlocked_compare_exchange;
ec.CurrentBranching.CurrentUsageVector.Goto ();
ig.Emit (OpCodes.Ldarg_0);
ig.Emit (OpCodes.Ldflda, host.PC.FieldBuilder);
- ig.Emit (OpCodes.Ldc_I4, (int) Iterator.State.Running);
+ ig.Emit (OpCodes.Ldc_I4, (int) Iterator.State.Start);
ig.Emit (OpCodes.Ldc_I4, (int) Iterator.State.Uninitialized);
ig.Emit (OpCodes.Call, ce);
return ec;
}
+ public override void EmitExtraSymbolInfo (SourceMethod source)
+ {
+ source.SetCompilerGenerated ();
+ }
+
protected class DisposeMethodStatement : Statement
{
Iterator iterator;
public override bool Resolve (EmitContext ec)
{
+ // We emit a 'ret', so prevent the enclosing TopLevelBlock from emitting one too
ec.CurrentBranching.CurrentUsageVector.Goto ();
return true;
}
protected override void DoEmit (EmitContext ec)
{
ILGenerator ig = ec.ig;
- Label label_ok = ig.DefineLabel ();
-
- ig.Emit (OpCodes.Ldarg_0);
- ig.Emit (OpCodes.Ldfld, host.PC.FieldBuilder);
- ig.Emit (OpCodes.Ldc_I4, (int) Iterator.State.Running);
- ig.Emit (OpCodes.Bgt, label_ok);
-
- ig.Emit (OpCodes.Newobj, host.GetInvalidOperationException ());
- ig.Emit (OpCodes.Throw);
- ig.MarkLabel (label_ok);
ig.Emit (OpCodes.Ldarg_0);
ig.Emit (OpCodes.Ldfld, host.CurrentField.FieldBuilder);
if (!is_generic)
// The state as we generate the iterator
//
Label move_next_ok, move_next_error;
- ArrayList resume_points = new ArrayList ();
- int pc;
-
+ LocalBuilder skip_finally, current_pc;
+
+ public LocalBuilder SkipFinally {
+ get { return skip_finally; }
+ }
+
+ public LocalBuilder CurrentPC {
+ get { return current_pc; }
+ }
+
public readonly Type OriginalIteratorType;
public readonly IteratorHost IteratorHost;
public enum State {
- Uninitialized = -2,
- After,
- Running
+ Running = -3, // Used only in CurrentPC, never stored into $PC
+ Uninitialized = -2,
+ After = -1,
+ Start = 0
+ }
+
+ public void EmitYieldBreak (ILGenerator ig, bool unwind_protect)
+ {
+ ig.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, move_next_error);
}
- public void EmitYieldBreak (ILGenerator ig)
+ void EmitMoveNext_NoResumePoints (EmitContext ec, Block original_block)
{
+ ILGenerator ig = ec.ig;
+
+ ig.Emit (OpCodes.Ldarg_0);
+ ig.Emit (OpCodes.Ldfld, IteratorHost.PC.FieldBuilder);
+
ig.Emit (OpCodes.Ldarg_0);
IntConstant.EmitInt (ig, (int) State.After);
ig.Emit (OpCodes.Stfld, IteratorHost.PC.FieldBuilder);
- ig.Emit (OpCodes.Br, move_next_error);
+
+ // We only care if the PC is zero (start executing) or non-zero (don't do anything)
+ ig.Emit (OpCodes.Brtrue, move_next_error);
+
+ SymbolWriter.StartIteratorBody (ec.ig);
+ original_block.Emit (ec);
+ SymbolWriter.EndIteratorBody (ec.ig);
+
+ ig.MarkLabel (move_next_error);
+ ig.Emit (OpCodes.Ldc_I4_0);
+ ig.Emit (OpCodes.Ret);
}
internal void EmitMoveNext (EmitContext ec, Block original_block)
move_next_ok = ig.DefineLabel ();
move_next_error = ig.DefineLabel ();
- LocalBuilder retval = ec.GetTemporaryLocal (TypeManager.int32_type);
-
- ig.BeginExceptionBlock ();
-
- Label dispatcher = ig.DefineLabel ();
- ig.Emit (OpCodes.Br, dispatcher);
+ if (resume_points == null) {
+ EmitMoveNext_NoResumePoints (ec, original_block);
+ return;
+ }
- ResumePoint entry_point = new ResumePoint (null);
- resume_points.Add (entry_point);
- entry_point.Define (ig);
+ current_pc = ec.GetTemporaryLocal (TypeManager.uint32_type);
+ ig.Emit (OpCodes.Ldarg_0);
+ ig.Emit (OpCodes.Ldfld, IteratorHost.PC.FieldBuilder);
+ ig.Emit (OpCodes.Stloc, current_pc);
- original_block.Emit (ec);
+ // We're actually in state 'running', but this is as good a PC value as any if there's an abnormal exit
+ ig.Emit (OpCodes.Ldarg_0);
+ IntConstant.EmitInt (ig, (int) State.After);
+ ig.Emit (OpCodes.Stfld, IteratorHost.PC.FieldBuilder);
- EmitYieldBreak (ig);
+ Label [] labels = new Label [1 + resume_points.Count];
+ labels [0] = ig.DefineLabel ();
- ig.MarkLabel (dispatcher);
+ bool need_skip_finally = false;
+ for (int i = 0; i < resume_points.Count; ++i) {
+ ResumableStatement s = (ResumableStatement) resume_points [i];
+ need_skip_finally |= s is ExceptionStatement;
+ labels [i+1] = s.PrepareForEmit (ec);
+ }
- Label [] labels = new Label [resume_points.Count];
- for (int i = 0; i < labels.Length; i++)
- labels [i] = ((ResumePoint) resume_points [i]).Label;
+ if (need_skip_finally) {
+ skip_finally = ec.GetTemporaryLocal (TypeManager.bool_type);
+ ig.Emit (OpCodes.Ldc_I4_0);
+ ig.Emit (OpCodes.Stloc, skip_finally);
+ }
- ig.Emit (OpCodes.Ldarg_0);
- ig.Emit (OpCodes.Ldfld, IteratorHost.PC.FieldBuilder);
+ SymbolWriter.StartIteratorDispatcher (ec.ig);
+ ig.Emit (OpCodes.Ldloc, current_pc);
ig.Emit (OpCodes.Switch, labels);
- Label end = ig.DefineLabel ();
+ ig.Emit (OpCodes.Br, move_next_error);
+ SymbolWriter.EndIteratorDispatcher (ec.ig);
- ig.MarkLabel (move_next_error);
- ig.Emit (OpCodes.Ldc_I4_0);
- ig.Emit (OpCodes.Stloc, retval);
- ig.Emit (OpCodes.Leave, end);
+ ig.MarkLabel (labels [0]);
- ig.MarkLabel (move_next_ok);
- ig.Emit (OpCodes.Ldc_I4_1);
- ig.Emit (OpCodes.Stloc, retval);
- ig.Emit (OpCodes.Leave, end);
+ SymbolWriter.StartIteratorBody (ec.ig);
+ original_block.Emit (ec);
+ SymbolWriter.EndIteratorBody (ec.ig);
- ig.BeginFaultBlock ();
+ SymbolWriter.StartIteratorDispatcher (ec.ig);
ig.Emit (OpCodes.Ldarg_0);
- ig.Emit (OpCodes.Callvirt, IteratorHost.Dispose);
+ IntConstant.EmitInt (ig, (int) State.After);
+ ig.Emit (OpCodes.Stfld, IteratorHost.PC.FieldBuilder);
- ig.EndExceptionBlock ();
+ ig.MarkLabel (move_next_error);
+ ig.Emit (OpCodes.Ldc_I4_0);
+ ig.Emit (OpCodes.Ret);
- ig.MarkLabel (end);
- ig.Emit (OpCodes.Ldloc, retval);
+ ig.MarkLabel (move_next_ok);
+ ig.Emit (OpCodes.Ldc_I4_1);
ig.Emit (OpCodes.Ret);
+
+ SymbolWriter.EndIteratorDispatcher (ec.ig);
}
public void EmitDispose (EmitContext ec)
ILGenerator ig = ec.ig;
Label end = ig.DefineLabel ();
- Label dispatcher = ig.DefineLabel ();
- ig.Emit (OpCodes.Br, dispatcher);
- Label [] labels = new Label [resume_points.Count];
- for (int i = 0; i < labels.Length; i++) {
- ResumePoint point = (ResumePoint) resume_points [i];
-
- if (point.FinallyBlocks == null) {
- labels [i] = end;
+ Label [] labels = null;
+ int n_resume_points = resume_points == null ? 0 : resume_points.Count;
+ for (int i = 0; i < n_resume_points; ++i) {
+ ResumableStatement s = (ResumableStatement) resume_points [i];
+ Label ret = s.PrepareForDispose (ec, end);
+ if (ret.Equals (end) && labels == null)
continue;
+ if (labels == null) {
+ labels = new Label [resume_points.Count + 1];
+ for (int j = 0; j <= i; ++j)
+ labels [j] = end;
}
-
- labels [i] = ig.DefineLabel ();
- ig.MarkLabel (labels [i]);
-
- ig.BeginExceptionBlock ();
- ig.BeginFinallyBlock ();
-
- foreach (ExceptionStatement stmt in point.FinallyBlocks) {
- if (stmt != null)
- stmt.EmitFinally (ec);
- }
-
- ig.EndExceptionBlock ();
- ig.Emit (OpCodes.Br, end);
+ labels [i+1] = ret;
}
- ig.MarkLabel (dispatcher);
- ig.Emit (OpCodes.Ldarg_0);
- ig.Emit (OpCodes.Ldfld, IteratorHost.PC.FieldBuilder);
- ig.Emit (OpCodes.Switch, labels);
+ if (labels != null) {
+ current_pc = ec.GetTemporaryLocal (TypeManager.uint32_type);
+ ig.Emit (OpCodes.Ldarg_0);
+ ig.Emit (OpCodes.Ldfld, IteratorHost.PC.FieldBuilder);
+ ig.Emit (OpCodes.Stloc, current_pc);
+ }
ig.Emit (OpCodes.Ldarg_0);
IntConstant.EmitInt (ig, (int) State.After);
ig.Emit (OpCodes.Stfld, IteratorHost.PC.FieldBuilder);
+ if (labels != null) {
+ //SymbolWriter.StartIteratorDispatcher (ec.ig);
+ ig.Emit (OpCodes.Ldloc, current_pc);
+ ig.Emit (OpCodes.Switch, labels);
+ //SymbolWriter.EndIteratorDispatcher (ec.ig);
+
+ foreach (ResumableStatement s in resume_points)
+ s.EmitForDispose (ec, this, end, true);
+ }
+
ig.MarkLabel (end);
}
- protected class ResumePoint
+ ArrayList resume_points;
+ public int AddResumePoint (ResumableStatement stmt, Location loc)
{
- public Label Label;
- public readonly ExceptionStatement[] FinallyBlocks;
-
- public ResumePoint (ArrayList list)
- {
- if (list != null) {
- FinallyBlocks = new ExceptionStatement [list.Count];
- list.CopyTo (FinallyBlocks, 0);
- }
- }
-
- public void Define (ILGenerator ig)
- {
- Label = ig.DefineLabel ();
- ig.MarkLabel (Label);
- }
+ if (resume_points == null)
+ resume_points = new ArrayList ();
+ resume_points.Add (stmt);
+ return resume_points.Count;
}
//
// Called back from Yield
//
- public void MarkYield (EmitContext ec, Expression expr,
- ArrayList finally_blocks)
+ public void MarkYield (EmitContext ec, Expression expr, int resume_pc, bool unwind_protect, Label resume_point)
{
ILGenerator ig = ec.ig;
expr.Emit (ec);
ig.Emit (OpCodes.Stfld, IteratorHost.CurrentField.FieldBuilder);
- // increment pc
- pc++;
+ // store resume program-counter
ig.Emit (OpCodes.Ldarg_0);
- IntConstant.EmitInt (ig, pc);
+ IntConstant.EmitInt (ig, resume_pc);
ig.Emit (OpCodes.Stfld, IteratorHost.PC.FieldBuilder);
- // Return ok
- ig.Emit (OpCodes.Br, move_next_ok);
-
- ResumePoint point = new ResumePoint (finally_blocks);
- resume_points.Add (point);
- point.Define (ig);
- }
-
- public void MarkFinally (EmitContext ec, ArrayList finally_blocks)
- {
- ILGenerator ig = ec.ig;
+ // mark finally blocks as disabled
+ if (unwind_protect && skip_finally != null) {
+ ig.Emit (OpCodes.Ldc_I4_1);
+ ig.Emit (OpCodes.Stloc, skip_finally);
+ }
- // increment pc
- pc++;
- ig.Emit (OpCodes.Ldarg_0);
- IntConstant.EmitInt (ig, pc);
- ig.Emit (OpCodes.Stfld, IteratorHost.PC.FieldBuilder);
+ // Return ok
+ ig.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, move_next_ok);
- ResumePoint point = new ResumePoint (finally_blocks);
- resume_points.Add (point);
- point.Define (ig);
+ ig.MarkLabel (resume_point);
}
public override string ContainerType {
{
Report.Debug (128, "CREATE METHOD HOST", this, IteratorHost);
+ MemberCore mc = ec.ResolveContext as MemberCore;
+
IteratorHost.CaptureScopes ();
return new AnonymousMethodMethod (
this, RootScope, null, TypeManager.system_boolean_expr,
- Modifiers.PUBLIC, new MemberName ("MoveNext", Location),
+ Modifiers.PUBLIC, mc.GetSignatureForError (),
+ new MemberName ("MoveNext", Location),
Parameters.EmptyReadOnlyParameters);
}
throw new NotSupportedException ();
}
- protected class MoveNextStatement : Statement {
- Iterator iterator;
-
- public MoveNextStatement (Iterator iterator, Location loc)
- {
- this.loc = loc;
- this.iterator = iterator;
- }
-
- public override bool Resolve (EmitContext ec)
- {
- return iterator.OriginalBlock.Resolve (ec);
- }
-
- protected override void DoEmit (EmitContext ec)
- {
- iterator.EmitMoveNext (ec, iterator.Block);
- }
- }
-
public Type IteratorType {
get { return IteratorHost.IteratorType; }
}
}
}
+ public override Expression CreateExpressionTree (EmitContext ec)
+ {
+ throw new NotSupportedException ("ET");
+ }
+
public static Iterator CreateIterator (IMethodData method, DeclSpace parent,
GenericMethod generic, int modifiers)
{