X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fgmcs%2Fiterators.cs;h=bcf063369782967a30c8cfdeaebe8436d01f1729;hb=49a4670f73ef631a93cd53d1c5e4eeb029eba8d0;hp=d571d5463786d49a90aba213d1e5855bc6cecf33;hpb=c884cdbe40bbd5b7fa9678c206d9168045d786cd;p=mono.git diff --git a/mcs/gmcs/iterators.cs b/mcs/gmcs/iterators.cs index d571d546378..bcf06336978 100644 --- a/mcs/gmcs/iterators.cs +++ b/mcs/gmcs/iterators.cs @@ -31,7 +31,7 @@ namespace Mono.CSharp { public class Yield : Statement { public Expression expr; - bool in_exc; + ArrayList finally_blocks; public Yield (Expression expr, Location l) { @@ -71,19 +71,21 @@ namespace Mono.CSharp { if (!CheckContext (ec, loc)) return false; - in_exc = ec.CurrentBranching.InTryOrCatch (false); - Type iterator_type = ec.CurrentIterator.IteratorType; - if (expr.Type != iterator_type){ - expr = Convert.ImplicitConversionRequired (ec, expr, iterator_type, loc); + Iterator iterator = ec.CurrentIterator; + if (expr.Type != iterator.IteratorType){ + expr = Convert.ImplicitConversionRequired ( + ec, expr, iterator.IteratorType, loc); if (expr == null) return false; } + + ec.CurrentBranching.StealFinallyClauses (ref finally_blocks); return true; } protected override void DoEmit (EmitContext ec) { - ec.CurrentIterator.MarkYield (ec, expr, in_exc); + ec.CurrentIterator.MarkYield (ec, expr, finally_blocks); } } @@ -105,11 +107,12 @@ namespace Mono.CSharp { protected override void DoEmit (EmitContext ec) { - ec.CurrentIterator.EmitYieldBreak (ec.ig, true); + ec.CurrentIterator.EmitYieldBreak (ec.ig); } } public class Iterator : Class { + string original_name; Block original_block; Block block; @@ -118,10 +121,13 @@ namespace Mono.CSharp { bool is_enumerable; bool is_static; + Hashtable fields; + // // The state as we generate the iterator // - ArrayList resume_labels = new ArrayList (); + Label move_next_ok, move_next_error; + ArrayList resume_points = new ArrayList (); int pc; // @@ -132,48 +138,146 @@ namespace Mono.CSharp { Type [] param_types; InternalParameters parameters; + Expression enumerator_type; + Expression enumerable_type; + Expression generic_enumerator_type; + Expression generic_enumerable_type; + TypeArguments generic_args; + + protected enum State { + Uninitialized = -2, + After, + Running + } + static int proxy_count; - public void EmitYieldBreak (ILGenerator ig, bool add_return) + public void EmitYieldBreak (ILGenerator ig) { ig.Emit (OpCodes.Ldarg_0); - IntConstant.EmitInt (ig, -1); - ig.Emit (OpCodes.Stfld, pc_field.FieldBuilder); - if (add_return){ - ig.Emit (OpCodes.Ldc_I4_0); - ig.Emit (OpCodes.Ret); - } + IntConstant.EmitInt (ig, (int) State.After); + ig.Emit (OpCodes.Br, move_next_error); } public void EmitMoveNext (EmitContext ec) { ILGenerator ig = ec.ig; + 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); - Label entry_point = ig.DefineLabel (); - ig.MarkLabel (entry_point); - resume_labels.Add (entry_point); - - ec.EmitTopBlock (original_block, parameters, Location); - EmitYieldBreak (ig, true); + ResumePoint entry_point = new ResumePoint (null); + resume_points.Add (entry_point); + entry_point.Define (ig); + + ec.EmitTopBlock (original_block, parameters, Location); + EmitYieldBreak (ig); - // - // FIXME: Split the switch in blocks that can be consumed - // by switch. - // ig.MarkLabel (dispatcher); - Label [] labels = new Label [resume_labels.Count]; - resume_labels.CopyTo (labels); + Label [] labels = new Label [resume_points.Count]; + for (int i = 0; i < labels.Length; i++) + labels [i] = ((ResumePoint) resume_points [i]).Label; + ig.Emit (OpCodes.Ldarg_0); ig.Emit (OpCodes.Ldfld, pc_field.FieldBuilder); ig.Emit (OpCodes.Switch, labels); - ig.Emit (OpCodes.Ldc_I4_0); + + Label end = ig.DefineLabel (); + + ig.MarkLabel (move_next_error); + ig.Emit (OpCodes.Ldc_I4_0); + ig.Emit (OpCodes.Stloc, retval); + ig.Emit (OpCodes.Leave, end); + + ig.MarkLabel (move_next_ok); + ig.Emit (OpCodes.Ldc_I4_1); + ig.Emit (OpCodes.Stloc, retval); + ig.Emit (OpCodes.Leave, end); + + ig.BeginFaultBlock (); + + ig.Emit (OpCodes.Ldarg_0); + ig.Emit (OpCodes.Callvirt, dispose.MethodBuilder); + + ig.EndExceptionBlock (); + + ig.MarkLabel (end); + ig.Emit (OpCodes.Ldloc, retval); ig.Emit (OpCodes.Ret); } + 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; + continue; + } + + 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); + } + + ig.MarkLabel (dispatcher); + ig.Emit (OpCodes.Ldarg_0); + ig.Emit (OpCodes.Ldfld, pc_field.FieldBuilder); + ig.Emit (OpCodes.Switch, labels); + + ig.Emit (OpCodes.Ldarg_0); + IntConstant.EmitInt (ig, (int) State.After); + ig.Emit (OpCodes.Stfld, pc_field.FieldBuilder); + + ig.MarkLabel (end); + } + + protected class ResumePoint + { + 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); + } + } + // // Invoked when a local variable declaration needs to be mapped to // a field in our proxy class @@ -184,13 +288,21 @@ namespace Mono.CSharp { // public FieldBuilder MapVariable (string pfx, string name, Type t) { - return TypeBuilder.DefineField (pfx + name, t, FieldAttributes.Public); + string full_name = pfx + name; + FieldBuilder fb = (FieldBuilder) fields [full_name]; + if (fb != null) + return fb; + + fb = TypeBuilder.DefineField (full_name, t, FieldAttributes.Private); + fields.Add (full_name, fb); + return fb; } - + // // Called back from Yield // - public void MarkYield (EmitContext ec, Expression expr, bool in_exc) + public void MarkYield (EmitContext ec, Expression expr, + ArrayList finally_blocks) { ILGenerator ig = ec.ig; @@ -206,29 +318,35 @@ namespace Mono.CSharp { ig.Emit (OpCodes.Stfld, pc_field.FieldBuilder); // Return ok - ig.Emit (OpCodes.Ldc_I4_1); - - // Find out how to "leave" - if (in_exc || !ec.IsLastStatement){ - Type old = ec.ReturnType; - ec.ReturnType = TypeManager.int32_type; - ig.Emit (OpCodes.Stloc, ec.TemporaryReturn ()); - ec.ReturnType = old; - } - - if (in_exc){ - ec.NeedReturnLabel (); - ig.Emit (OpCodes.Leave, ec.ReturnLabel); - } else if (ec.IsLastStatement){ - ig.Emit (OpCodes.Ret); - } else { - ec.NeedReturnLabel (); - ig.Emit (OpCodes.Br, ec.ReturnLabel); - } - - Label resume_point = ig.DefineLabel (); - ig.MarkLabel (resume_point); - resume_labels.Add (resume_point); + 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; + + // increment pc + pc++; + ig.Emit (OpCodes.Ldarg_0); + IntConstant.EmitInt (ig, pc); + ig.Emit (OpCodes.Stfld, pc_field.FieldBuilder); + + ResumePoint point = new ResumePoint (finally_blocks); + resume_points.Add (point); + point.Define (ig); + } + + private static MemberName MakeProxyName (string name) + { + int pos = name.LastIndexOf ('.'); + if (pos > 0) + name = name.Substring (pos + 1); + + return new MemberName ("<" + name + ">__" + (proxy_count++)); } // @@ -237,30 +355,30 @@ namespace Mono.CSharp { public Iterator (TypeContainer container, string name, Type return_type, Type [] param_types, InternalParameters parameters, int modifiers, Block block, Location loc) - : base (container.NamespaceEntry, container, - "", + : base (container.NamespaceEntry, container, MakeProxyName (name), Modifiers.PRIVATE, null, loc) { this.container = container; this.return_type = return_type; this.param_types = param_types; this.parameters = parameters; + this.original_name = name; this.original_block = block; this.block = new Block (null); - is_static = (modifiers & Modifiers.STATIC) != 0; + fields = new Hashtable (); - container.AddIterator (this); + is_static = (modifiers & Modifiers.STATIC) != 0; } - public bool Define () + public bool DefineIterator () { if (!CheckType (return_type)) { Report.Error ( 1624, Location, "The body of `{0}' cannot be an iterator block " + "because '{1}' is not an iterator interface type", - Name, TypeManager.CSharpName (return_type)); + original_name, TypeManager.CSharpName (return_type)); return false; } @@ -274,15 +392,36 @@ namespace Mono.CSharp { } } + generic_args = new TypeArguments (Location); + generic_args.Add (new TypeExpression (iterator_type, Location)); + ArrayList list = new ArrayList (); - if (is_enumerable) - list.Add (new TypeExpression ( - TypeManager.ienumerable_type, Location)); - list.Add (new TypeExpression (TypeManager.ienumerator_type, Location)); + if (is_enumerable) { + enumerable_type = new TypeExpression ( + TypeManager.ienumerable_type, Location); + list.Add (enumerable_type); + + generic_enumerable_type = new ConstructedType ( + TypeManager.generic_ienumerable_type, + generic_args, Location); + list.Add (generic_enumerable_type); + } + + enumerator_type = new TypeExpression ( + TypeManager.ienumerator_type, Location); + list.Add (enumerator_type); + list.Add (new TypeExpression (TypeManager.idisposable_type, Location)); + generic_enumerator_type = new ConstructedType ( + TypeManager.generic_ienumerator_type, + generic_args, Location); + list.Add (generic_enumerator_type); + iterator_type_expr = new TypeExpression (iterator_type, Location); + container.AddIterator (this); + Bases = list; return true; } @@ -290,26 +429,31 @@ namespace Mono.CSharp { // // Returns the new block for the method, or null on failure // - protected override bool DoDefineType () + protected override bool DefineNestedTypes () { Define_Fields (); Define_Constructor (); - Define_Current (); + Define_Current (false); + Define_Current (true); Define_MoveNext (); Define_Reset (); Define_Dispose (); - if (is_enumerable) - Define_GetEnumerator (); + if (is_enumerable) { + Define_GetEnumerator (false); + Define_GetEnumerator (true); + } Create_Block (); - return true; + return base.DefineNestedTypes (); } Field pc_field; Field current_field; + Method dispose; + public Field this_field; public Field[] parameter_fields; @@ -321,15 +465,15 @@ namespace Mono.CSharp { if (!is_static) { Type t = container.TypeBuilder; args.Add (new Argument ( - new SimpleParameterReference (t, 0, Location), - Argument.AType.Expression)); + new ThisParameterReference (t, 0, Location))); } + args.Add (new Argument (new BoolLiteral (false))); + for (int i = 0; i < parameters.Count; i++) { Type t = parameters.ParameterType (i); args.Add (new Argument ( - new SimpleParameterReference (t, first + i, Location), - Argument.AType.Expression)); + new SimpleParameterReference (t, first + i, Location))); } Expression new_expr = new New ( @@ -343,17 +487,18 @@ namespace Mono.CSharp { Location loc = Location.Null; pc_field = new Field ( - TypeManager.system_int32_expr, Modifiers.PRIVATE, "PC", + this, TypeManager.system_int32_expr, Modifiers.PRIVATE, "PC", null, null, loc); AddField (pc_field); current_field = new Field ( - iterator_type_expr, Modifiers.PRIVATE, "current", + this, iterator_type_expr, Modifiers.PRIVATE, "current", null, null, loc); AddField (current_field); if (!is_static) { this_field = new Field ( + this, new TypeExpression (container.TypeBuilder, Location), Modifiers.PRIVATE, "this", null, null, loc); AddField (this_field); @@ -365,6 +510,7 @@ namespace Mono.CSharp { "field{0}_{1}", i, parameters.ParameterName (i)); parameter_fields [i] = new Field ( + this, new TypeExpression (parameters.ParameterType (i), loc), Modifiers.PRIVATE, fname, null, null, loc); AddField (parameter_fields [i]); @@ -375,21 +521,26 @@ namespace Mono.CSharp { { Parameters ctor_params; - if (!is_static) { - Parameter this_param = new Parameter ( + ArrayList list = new ArrayList (); + + if (!is_static) + list.Add (new Parameter ( new TypeExpression (container.TypeBuilder, Location), - "this", Parameter.Modifier.NONE, null); + "this", Parameter.Modifier.NONE, null)); + list.Add (new Parameter ( + TypeManager.system_boolean_expr, "initialized", + Parameter.Modifier.NONE, null)); - Parameter[] old_fixed = parameters.Parameters.FixedParameters; - Parameter[] fixed_params = new Parameter [old_fixed.Length + 1]; - fixed_params [0] = this_param; - old_fixed.CopyTo (fixed_params, 1); + Parameter[] old_fixed = parameters.Parameters.FixedParameters; + if (old_fixed != null) + list.AddRange (old_fixed); - ctor_params = new Parameters ( - fixed_params, parameters.Parameters.ArrayParameter, - Location); - } else - ctor_params = parameters.Parameters; + Parameter[] fixed_params = new Parameter [list.Count]; + list.CopyTo (fixed_params); + + ctor_params = new Parameters ( + fixed_params, parameters.Parameters.ArrayParameter, + Location); Constructor ctor = new Constructor ( this, Name, Modifiers.PUBLIC, ctor_params, @@ -411,7 +562,7 @@ namespace Mono.CSharp { block.AddStatement (new StatementExpression (assign, Location)); } - int first = is_static ? 1 : 2; + int first = is_static ? 2 : 3; for (int i = 0; i < parameters.Count; i++) { Type t = parameters.ParameterType (i); @@ -423,6 +574,15 @@ namespace Mono.CSharp { block.AddStatement (new StatementExpression (assign, Location)); } + + State initial = is_enumerable ? State.Uninitialized : State.Running; + block.AddStatement (new SetState (this, initial, Location)); + + block.AddStatement (new If ( + new SimpleParameterReference ( + TypeManager.bool_type, first - 1, Location), + new SetState (this, State.Running, Location), + Location)); } Statement Create_ThrowInvalidOperation () @@ -441,15 +601,29 @@ namespace Mono.CSharp { return new Throw (new New (ex_type, null, Location), Location); } - void Define_Current () + void Define_Current (bool is_generic) { + MemberName left; + Expression type; + if (is_generic) { + left = new MemberName ( + "System.Collections.Generic.IEnumerator", + generic_args); + type = iterator_type_expr; + } else { + left = new MemberName ("System.Collections.IEnumerator"); + type = TypeManager.system_object_expr; + } + + MemberName name = new MemberName (left, "Current", null); + Block get_block = new Block (null); get_block.AddStatement (new If ( new Binary ( Binary.Operator.LessThanOrEqual, new FieldExpression (pc_field), - new IntLiteral (0), Location), + new IntLiteral ((int) State.Running), Location), Create_ThrowInvalidOperation (), new Return ( new FieldExpression (current_field), Location), @@ -458,16 +632,15 @@ namespace Mono.CSharp { Accessor getter = new Accessor (get_block, null); Property current = new Property ( - this, iterator_type_expr, Modifiers.PUBLIC, - false, "Current", null, getter, null, Location); + this, type, 0, false, name, null, getter, null, Location); AddProperty (current); } void Define_MoveNext () { Method move_next = new Method ( - this, TypeManager.system_boolean_expr, - Modifiers.PUBLIC, false, "MoveNext", + this, null, TypeManager.system_boolean_expr, + Modifiers.PUBLIC, false, new MemberName ("MoveNext"), Parameters.EmptyReadOnlyParameters, null, Location.Null); AddMethod (move_next); @@ -478,20 +651,64 @@ namespace Mono.CSharp { block.AddStatement (inline); } - void Define_GetEnumerator () + void Define_GetEnumerator (bool is_generic) { + MemberName left; + Expression type; + if (is_generic) { + left = new MemberName ( + "System.Collections.Generic.IEnumerable", + generic_args); + type = generic_enumerator_type; + } else { + left = new MemberName ("System.Collections.IEnumerable"); + type = enumerator_type; + } + + MemberName name = new MemberName (left, "GetEnumerator", null); + Method get_enumerator = new Method ( - this, - new TypeExpression (TypeManager.ienumerator_type, Location), - Modifiers.PUBLIC, false, "GetEnumerator", + this, null, type, 0, false, name, Parameters.EmptyReadOnlyParameters, null, Location.Null); AddMethod (get_enumerator); get_enumerator.Block = new Block (null); - This the_this = new This (block, Location); - get_enumerator.Block.AddStatement (new Return (the_this, Location)); + Expression ce = new MemberAccess ( + new SimpleName ("System.Threading.Interlocked", Location), + "CompareExchange", Location); + + Expression pc = new FieldExpression (pc_field); + Expression before = new IntLiteral ((int) State.Running); + Expression uninitialized = new IntLiteral ((int) State.Uninitialized); + + ArrayList args = new ArrayList (); + args.Add (new Argument (pc, Argument.AType.Ref)); + args.Add (new Argument (before, Argument.AType.Expression)); + args.Add (new Argument (uninitialized, Argument.AType.Expression)); + + get_enumerator.Block.AddStatement (new If ( + new Binary ( + Binary.Operator.Equality, + new Invocation (ce, args, Location), + uninitialized, Location), + new Return (new This (block, Location), Location), + Location)); + + args = new ArrayList (); + if (!is_static) + args.Add (new Argument (new FieldExpression (this_field))); + + args.Add (new Argument (new BoolLiteral (true))); + + for (int i = 0; i < parameters.Count; i++) + args.Add (new Argument ( + new FieldExpression (parameter_fields [i]))); + + Expression new_expr = new New ( + new TypeExpression (TypeBuilder, Location), args, Location); + get_enumerator.Block.AddStatement (new Return (new_expr, Location)); } protected class SimpleParameterReference : Expression @@ -512,11 +729,30 @@ namespace Mono.CSharp { } public override void Emit (EmitContext ec) + { + DoEmit (ec); + } + + protected virtual void DoEmit (EmitContext ec) { ParameterReference.EmitLdArg (ec.ig, idx); } } + protected class ThisParameterReference : SimpleParameterReference + { + public ThisParameterReference (Type type, int idx, Location loc) + : base (type, idx, loc) + { } + + protected override void DoEmit (EmitContext ec) + { + base.DoEmit (ec); + if (ec.TypeContainer is Struct) + ec.ig.Emit (OpCodes.Ldobj, type); + } + } + protected class FieldExpression : Expression { Field field; @@ -539,7 +775,7 @@ namespace Mono.CSharp { } } - public class MoveNextMethod : Statement { + protected class MoveNextMethod : Statement { Iterator iterator; public MoveNextMethod (Iterator iterator, Location loc) @@ -561,8 +797,8 @@ namespace Mono.CSharp { code_flags |= Modifiers.STATIC; EmitContext new_ec = new EmitContext ( - iterator, loc, ec.ig, iterator.return_type, - code_flags); + iterator.container, loc, ec.ig, + TypeManager.int32_type, code_flags); new_ec.CurrentIterator = iterator; @@ -570,38 +806,88 @@ namespace Mono.CSharp { } } - protected class DoYieldBreak : Statement + protected class DisposeMethod : Statement { + Iterator iterator; + + public DisposeMethod (Iterator iterator, Location loc) + { + this.loc = loc; + this.iterator = iterator; + } + + public override bool Resolve (EmitContext ec) + { + return true; + } + + protected override void DoEmit (EmitContext ec) + { + iterator.EmitDispose (ec); + } + } + + protected class StatementList : Statement { + ArrayList statements; + + public StatementList (Location loc) + { + this.loc = loc; + statements = new ArrayList (); + } + + public void Add (Statement statement) + { + statements.Add (statement); + } + + public override bool Resolve (EmitContext ec) + { + foreach (Statement stmt in statements) { + if (!stmt.Resolve (ec)) + return false; + } + + return true; + } + + protected override void DoEmit (EmitContext ec) + { + foreach (Statement stmt in statements) + stmt.Emit (ec); + } + } + + protected class SetState : Statement { Iterator iterator; - bool add_return; + State state; - public DoYieldBreak (Iterator iterator, bool add_return, - Location loc) + public SetState (Iterator iterator, State state, Location loc) { this.iterator = iterator; - this.add_return = add_return; + this.state = state; this.loc = loc; } public override bool Resolve (EmitContext ec) { - if (add_return) - ec.CurrentBranching.CurrentUsageVector.Return (); return true; } protected override void DoEmit (EmitContext ec) { - iterator.EmitYieldBreak (ec.ig, add_return); + ec.ig.Emit (OpCodes.Ldarg_0); + IntConstant.EmitInt (ec.ig, (int) state); + ec.ig.Emit (OpCodes.Stfld, iterator.pc_field.FieldBuilder); } } void Define_Reset () { Method reset = new Method ( - this, TypeManager.system_void_expr, Modifiers.PUBLIC, - false, "Reset", Parameters.EmptyReadOnlyParameters, - null, Location); + this, null, TypeManager.system_void_expr, Modifiers.PUBLIC, + false, new MemberName ("Reset"), + Parameters.EmptyReadOnlyParameters, null, Location); AddMethod (reset); reset.Block = new Block (null); @@ -610,15 +896,14 @@ namespace Mono.CSharp { void Define_Dispose () { - Method dispose = new Method ( - this, TypeManager.system_void_expr, Modifiers.PUBLIC, - false, "Dispose", Parameters.EmptyReadOnlyParameters, - null, Location); + dispose = new Method ( + this, null, TypeManager.system_void_expr, Modifiers.PUBLIC, + false, new MemberName ("Dispose"), + Parameters.EmptyReadOnlyParameters, null, Location); AddMethod (dispose); dispose.Block = new Block (null); - dispose.Block.AddStatement (new DoYieldBreak (this, false, Location)); - dispose.Block.AddStatement (new Return (null, Location)); + dispose.Block.AddStatement (new DisposeMethod (this, Location)); } public Block Block { @@ -660,6 +945,24 @@ namespace Mono.CSharp { return true; } + if (!t.IsGenericInstance) + return false; + + Type[] args = TypeManager.GetTypeArguments (t); + if (args.Length != 1) + return false; + + Type gt = t.GetGenericTypeDefinition (); + if (gt == TypeManager.generic_ienumerable_type) { + iterator_type = args [0]; + is_enumerable = true; + return true; + } else if (gt == TypeManager.generic_ienumerator_type) { + iterator_type = args [0]; + is_enumerable = false; + return true; + } + return false; } }