//
// TODO:
// Flow analysis for Yield.
-// Emit calls to parent object constructor.
+// Emit calls to base object constructor.
//
// Generics note:
// Current should be defined to return T, and IEnumerator.Current returns object
public class Yield : Statement {
public Expression expr;
- bool in_exc;
+ ArrayList finally_blocks;
public Yield (Expression expr, Location l)
{
public static bool CheckContext (EmitContext ec, Location loc)
{
if (ec.CurrentBranching.InFinally (true)){
- Report.Error (-208, loc, "yield statement can not appear in finally clause");
+ Report.Error (1625, loc, "Cannot yield in the body of a " +
+ "finally clause");
return false;
}
if (ec.CurrentBranching.InCatch ()){
- Report.Error (-209, loc, "yield statement can not appear in the catch clause");
+ Report.Error (1631, loc, "Cannot yield in the body of a " +
+ "catch clause");
return false;
}
- if (ec.InAnonymousMethod){
- Report.Error (-209, loc, "yield statement can not appear inside an anonymoud method");
+ if (ec.CurrentAnonymousMethod != null){
+ Report.Error (1621, loc, "yield statement can not appear inside an anonymoud method");
return false;
}
if (!CheckContext (ec, loc))
return false;
- in_exc = ec.CurrentBranching.InTryOrCatch (false);
- Type iterator_type = IteratorHandler.Current.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)
{
- IteratorHandler.Current.MarkYield (ec, expr, in_exc);
+ ec.CurrentIterator.MarkYield (ec, expr, finally_blocks);
}
}
protected override void DoEmit (EmitContext ec)
{
- IteratorHandler.Current.EmitYieldBreak (ec.ig, true);
+ ec.CurrentIterator.EmitYieldBreak (ec.ig);
}
}
- public class IteratorHandler {
- //
- // Points to the current iterator handler, will be probed by
- // Yield and YieldBreak to get their context information
- //
- public static IteratorHandler Current;
-
- //
- // The typebuilder to the proxy class we create
- //
- TypeBuilder enumerator_proxy_class;
- TypeBuilder enumerable_proxy_class;
+ public class Iterator : Class {
+ ToplevelBlock original_block;
+ ToplevelBlock block;
+ string original_name;
- //
- // The type of this iterator, object by default.
- //
- public Type IteratorType;
-
- //
- // The members we create on the proxy class
- //
- MethodBuilder move_next_method;
- MethodBuilder reset_method;
- MethodBuilder get_current_method;
- MethodBuilder dispose_method;
- MethodBuilder getenumerator_method;
- PropertyBuilder current_property;
- ConstructorBuilder enumerator_proxy_constructor;
- ConstructorBuilder enumerable_proxy_constructor;
+ Type iterator_type;
+ TypeExpr iterator_type_expr;
+ bool is_enumerable;
+ bool is_static;
- //
- // The PC for the state machine.
- //
- FieldBuilder pc_field;
-
- //
- // The value computed for Current
- //
- FieldBuilder current_field;
+ Hashtable fields;
- //
- // Used to reference fields on the container class (instance methods)
- //
- public FieldBuilder this_field;
- public FieldBuilder enumerable_this_field;
-
- //
- // References the parameters
- //
-
- public FieldBuilder [] parameter_fields;
- FieldBuilder [] enumerable_parameter_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;
//
// Context from the original method
//
- string name;
TypeContainer container;
+ TypeExpr current_type;
+ Type this_type;
Type return_type;
Type [] param_types;
InternalParameters parameters;
- Block original_block;
- Location loc;
- int modifiers;
+
+ MethodInfo dispose_method;
+
+ 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);
- if (add_return){
- ig.Emit (OpCodes.Ldc_I4_0);
- ig.Emit (OpCodes.Ret);
- }
+ IntConstant.EmitInt (ig, (int) State.After);
+ ig.Emit (OpCodes.Stfld, pc_field.FieldBuilder);
+ ig.Emit (OpCodes.Br, move_next_error);
}
- void EmitThrowInvalidOp (ILGenerator ig)
- {
- ig.Emit (OpCodes.Newobj, TypeManager.invalid_operation_ctor);
- ig.Emit (OpCodes.Throw);
- }
-
- void Create_MoveNext ()
+ public void EmitMoveNext (EmitContext ec)
{
- move_next_method = enumerator_proxy_class.DefineMethod (
- "System.IEnumerator.MoveNext",
- MethodAttributes.HideBySig | MethodAttributes.NewSlot |
- MethodAttributes.Virtual,
- CallingConventions.HasThis, TypeManager.bool_type, TypeManager.NoTypes);
- enumerator_proxy_class.DefineMethodOverride (move_next_method, TypeManager.bool_movenext_void);
+ ILGenerator ig = ec.ig;
- ILGenerator ig = move_next_method.GetILGenerator ();
- EmitContext ec = new EmitContext (
- container, loc, ig,
- TypeManager.void_type, modifiers);
+ 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);
-
- Current = this;
- SymbolWriter sw = CodeGen.SymbolWriter;
- if ((sw != null) && !Location.IsNull (loc) && !Location.IsNull (original_block.EndLocation)) {
- sw.OpenMethod (container, move_next_method, loc, original_block.EndLocation);
-
- ec.EmitTopBlock (original_block, parameters, loc);
-
- sw.CloseMethod ();
- } else {
- ec.EmitTopBlock (original_block, parameters, loc);
- }
- Current = null;
- 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);
+ ig.Emit (OpCodes.Ldfld, pc_field.FieldBuilder);
ig.Emit (OpCodes.Switch, labels);
- ig.Emit (OpCodes.Ldc_I4_0);
- ig.Emit (OpCodes.Ret);
- }
- //
- // Invoked when a local variable declaration needs to be mapped to
- // a field in our proxy class
- //
- // Prefixes registered:
- // v_ for EmitContext.MapVariable
- // s_ for Storage
- //
- public FieldBuilder MapVariable (string pfx, string name, Type t)
- {
- return enumerator_proxy_class.DefineField (pfx + name, t, FieldAttributes.Public);
- }
-
- void Create_Reset ()
- {
- reset_method = enumerator_proxy_class.DefineMethod (
- "System.IEnumerator.Reset",
- MethodAttributes.HideBySig | MethodAttributes.NewSlot |
- MethodAttributes.Virtual,
- CallingConventions.HasThis, TypeManager.void_type, TypeManager.NoTypes);
- enumerator_proxy_class.DefineMethodOverride (reset_method, TypeManager.void_reset_void);
- ILGenerator ig = reset_method.GetILGenerator ();
- EmitThrowInvalidOp (ig);
+ 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_method);
+
+ ig.EndExceptionBlock ();
+
+ ig.MarkLabel (end);
+ ig.Emit (OpCodes.Ldloc, retval);
+ ig.Emit (OpCodes.Ret);
}
- void Create_Current ()
+ public void EmitDispose (EmitContext ec)
{
- get_current_method = enumerator_proxy_class.DefineMethod (
- "System.IEnumerator.get_Current",
- MethodAttributes.HideBySig | MethodAttributes.SpecialName |
- MethodAttributes.NewSlot | MethodAttributes.Virtual,
- CallingConventions.HasThis, TypeManager.object_type, TypeManager.NoTypes);
- enumerator_proxy_class.DefineMethodOverride (get_current_method, TypeManager.object_getcurrent_void);
+ ILGenerator ig = ec.ig;
+
+ Label end = ig.DefineLabel ();
+ Label dispatcher = ig.DefineLabel ();
+ ig.Emit (OpCodes.Br, dispatcher);
+
+ ec.RemapToProxy = true;
+ Label [] labels = new Label [resume_points.Count];
+ for (int i = 0; i < labels.Length; i++) {
+ ResumePoint point = (ResumePoint) resume_points [i];
- current_property = enumerator_proxy_class.DefineProperty (
- "Current",
- PropertyAttributes.RTSpecialName | PropertyAttributes.SpecialName,
- TypeManager.object_type, null);
+ if (point.FinallyBlocks == null) {
+ labels [i] = end;
+ continue;
+ }
+
+ labels [i] = ig.DefineLabel ();
+ ig.MarkLabel (labels [i]);
+
+ ig.BeginExceptionBlock ();
+ ig.BeginFinallyBlock ();
- current_property.SetGetMethod (get_current_method);
-
- ILGenerator ig = get_current_method.GetILGenerator ();
+ foreach (ExceptionStatement stmt in point.FinallyBlocks) {
+ if (stmt != null)
+ stmt.EmitFinally (ec);
+ }
+
+ ig.EndExceptionBlock ();
+ ig.Emit (OpCodes.Br, end);
+ }
+ ec.RemapToProxy = false;
+ ig.MarkLabel (dispatcher);
ig.Emit (OpCodes.Ldarg_0);
- ig.Emit (OpCodes.Ldfld, pc_field);
- ig.Emit (OpCodes.Ldc_I4_0);
- Label return_current = ig.DefineLabel ();
- ig.Emit (OpCodes.Bgt, return_current);
- EmitThrowInvalidOp (ig);
-
- ig.MarkLabel (return_current);
+ ig.Emit (OpCodes.Ldfld, pc_field.FieldBuilder);
+ ig.Emit (OpCodes.Switch, labels);
+
ig.Emit (OpCodes.Ldarg_0);
- ig.Emit (OpCodes.Ldfld, current_field);
- ig.Emit (OpCodes.Ret);
+ IntConstant.EmitInt (ig, (int) State.After);
+ ig.Emit (OpCodes.Stfld, pc_field.FieldBuilder);
+
+ ig.MarkLabel (end);
}
- void Create_Dispose ()
+ protected class ResumePoint
{
- dispose_method = enumerator_proxy_class.DefineMethod (
- "System.IDisposable.Dispose",
- MethodAttributes.HideBySig | MethodAttributes.SpecialName |
- MethodAttributes.NewSlot | MethodAttributes.Virtual,
- CallingConventions.HasThis, TypeManager.void_type, TypeManager.NoTypes);
- enumerator_proxy_class.DefineMethodOverride (dispose_method, TypeManager.void_dispose_void);
- ILGenerator ig = dispose_method.GetILGenerator ();
+ public Label Label;
+ public readonly ExceptionStatement[] FinallyBlocks;
- EmitYieldBreak (ig, false);
- ig.Emit (OpCodes.Ret);
- }
-
- void Create_GetEnumerator ()
- {
- getenumerator_method = enumerable_proxy_class.DefineMethod (
- "IEnumerable.GetEnumerator",
- MethodAttributes.HideBySig | MethodAttributes.SpecialName |
- MethodAttributes.NewSlot | MethodAttributes.Virtual,
- CallingConventions.HasThis, TypeManager.ienumerator_type, TypeManager.NoTypes);
-
- enumerable_proxy_class.DefineMethodOverride (getenumerator_method, TypeManager.ienumerable_getenumerator_void);
- ILGenerator ig = getenumerator_method.GetILGenerator ();
-
- ig.Emit (OpCodes.Newobj, (ConstructorInfo) enumerator_proxy_constructor);
- if (enumerable_this_field != null || parameters.Count > 0){
- LocalBuilder obj = ig.DeclareLocal (enumerator_proxy_class);
- ig.Emit (OpCodes.Stloc, obj);
- if (enumerable_this_field != null){
- ig.Emit (OpCodes.Ldloc, obj);
- ig.Emit (OpCodes.Ldarg_0);
- ig.Emit (OpCodes.Ldfld, enumerable_this_field);
- ig.Emit (OpCodes.Stfld, this_field);
- }
-
- for (int i = 0; i < parameters.Count; i++){
- ig.Emit (OpCodes.Ldloc, obj);
- ig.Emit (OpCodes.Ldarg_0);
- ig.Emit (OpCodes.Ldfld, enumerable_parameter_fields [i]);
- ig.Emit (OpCodes.Stfld, parameter_fields [i]);
+ public ResumePoint (ArrayList list)
+ {
+ if (list != null) {
+ FinallyBlocks = new ExceptionStatement [list.Count];
+ list.CopyTo (FinallyBlocks, 0);
}
- ig.Emit (OpCodes.Ldloc, obj);
}
-
- ig.Emit (OpCodes.Ret);
+
+ 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
+ //
+ // Prefixes registered:
+ // v_ for EmitContext.MapVariable
+ // s_ for Storage
+ //
+ public FieldBuilder MapVariable (string pfx, string name, Type t)
+ {
+ 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;
// Store the new current
ig.Emit (OpCodes.Ldarg_0);
expr.Emit (ec);
- ig.Emit (OpCodes.Stfld, current_field);
+ ig.Emit (OpCodes.Stfld, current_field.FieldBuilder);
// increment pc
pc++;
ig.Emit (OpCodes.Ldarg_0);
IntConstant.EmitInt (ig, pc);
- ig.Emit (OpCodes.Stfld, pc_field);
+ 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++));
}
//
- // Creates the IEnumerator Proxy class
+ // Our constructor
//
- void MakeEnumeratorProxy ()
+ public Iterator (TypeContainer container, string name, Type return_type,
+ Type [] param_types, InternalParameters parameters,
+ int modifiers, ToplevelBlock block, Location loc)
+ : base (container.NamespaceEntry, container, MakeProxyName (name),
+ Modifiers.PRIVATE, null, loc)
{
- TypeExpr [] proxy_base_interfaces = new TypeExpr [2];
- proxy_base_interfaces [0] = new TypeExpression (TypeManager.ienumerator_type, loc);
- proxy_base_interfaces [1] = new TypeExpression (TypeManager.idisposable_type, loc);
- Type [] proxy_base_itypes = new Type [2];
- proxy_base_itypes [0] = TypeManager.ienumerator_type;
- proxy_base_itypes [1] = TypeManager.idisposable_type;
- TypeBuilder container_builder = container.TypeBuilder;
+ 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 ToplevelBlock (loc);
- //
- // Create the class
- //
- enumerator_proxy_class = container_builder.DefineNestedType (
- "<Enumerator:" + name + ":" + (proxy_count++) + ">",
- TypeAttributes.AutoLayout | TypeAttributes.Class |TypeAttributes.NestedPrivate,
- TypeManager.object_type, proxy_base_itypes);
+ fields = new Hashtable ();
- TypeManager.RegisterBuilder (enumerator_proxy_class, proxy_base_interfaces);
+ is_static = (modifiers & Modifiers.STATIC) != 0;
+ }
- //
- // Define our fields
- //
- pc_field = enumerator_proxy_class.DefineField ("PC", TypeManager.int32_type, FieldAttributes.Assembly);
- current_field = enumerator_proxy_class.DefineField ("current", IteratorType, FieldAttributes.Assembly);
- if ((modifiers & Modifiers.STATIC) == 0)
- this_field = enumerator_proxy_class.DefineField ("THIS", container.TypeBuilder, FieldAttributes.Assembly);
+ public bool DefineIterator ()
+ {
+ ec = new EmitContext (this, Mono.CSharp.Location.Null, null, null, ModFlags);
+
+ 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",
+ original_name, TypeManager.CSharpName (return_type));
+ return false;
+ }
- parameter_fields = new FieldBuilder [parameters.Count];
for (int i = 0; i < parameters.Count; i++){
- parameter_fields [i] = enumerator_proxy_class.DefineField (
- String.Format ("tor{0}_{1}", i, parameters.ParameterName (i)),
- parameters.ParameterType (i), FieldAttributes.Assembly);
+ Parameter.Modifier mod = parameters.ParameterModifier (i);
+ if ((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) != 0){
+ Report.Error (
+ 1623, Location,
+ "Iterators cannot have ref or out parameters");
+ return false;
+ }
}
-
- //
- // Define a constructor
- //
- enumerator_proxy_constructor = enumerator_proxy_class.DefineConstructor (
- MethodAttributes.Public | MethodAttributes.HideBySig |
- MethodAttributes.SpecialName | MethodAttributes.RTSpecialName,
- CallingConventions.HasThis, TypeManager.NoTypes);
- InternalParameters parameter_info = new InternalParameters (
- TypeManager.NoTypes, Parameters.EmptyReadOnlyParameters);
- TypeManager.RegisterMethod (enumerator_proxy_constructor, parameter_info, TypeManager.NoTypes);
+ if (container.CurrentType != null)
+ this_type = container.CurrentType;
+ else
+ this_type = container.TypeBuilder;
- //
- // Our constructor
- //
- ILGenerator ig = enumerator_proxy_constructor.GetILGenerator ();
- ig.Emit (OpCodes.Ldarg_0);
- ig.Emit (OpCodes.Call, TypeManager.object_ctor);
+ generic_args = new TypeArguments (Location);
+ generic_args.Add (new TypeExpression (iterator_type, Location));
- ig.Emit (OpCodes.Ret);
+ ArrayList list = new ArrayList ();
+ 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;
+ }
+
+ MethodInfo FetchMethodDispose ()
+ {
+ MemberList dispose_list;
+
+ dispose_list = FindMembers (
+ current_type.Type,
+ MemberTypes.Method, BindingFlags.Public | BindingFlags.Instance,
+ Type.FilterName, "Dispose");
+
+ if (dispose_list.Count != 1)
+ throw new InternalErrorException ("Cannot find Dipose() method.");
+
+ return (MethodInfo) dispose_list [0];
+ }
+
+ protected override bool DoDefineMembers ()
+ {
+ if (!base.DoDefineMembers ())
+ return false;
+
+ dispose_method = FetchMethodDispose ();
+ if (dispose_method == null)
+ return false;
+
+ return true;
}
//
- // Creates the IEnumerable proxy class
+ // Returns the new block for the method, or null on failure
//
- void MakeEnumerableProxy ()
+ protected override bool DefineNestedTypes ()
{
- TypeBuilder container_builder = container.TypeBuilder;
- Type [] proxy_base_interfaces = new Type [1];
- proxy_base_interfaces [0] = TypeManager.ienumerable_type;
+ if (CurrentType != null)
+ current_type = new TypeExpression (CurrentType, Location);
+ else
+ current_type = new TypeExpression (TypeBuilder, Location);
+
+ Define_Fields ();
+ Define_Constructor ();
+ Define_Current (false);
+ Define_Current (true);
+ Define_MoveNext ();
+ Define_Reset ();
+ Define_Dispose ();
+
+ if (is_enumerable) {
+ Define_GetEnumerator (false);
+ Define_GetEnumerator (true);
+ }
- //
- // Creates the Enumerable proxy class.
- //
- enumerable_proxy_class = container_builder.DefineNestedType (
- "<Enumerable:" + name + ":" + (proxy_count++)+ ">",
- TypeAttributes.AutoLayout | TypeAttributes.Class |TypeAttributes.NestedPublic,
- TypeManager.object_type, proxy_base_interfaces);
+ Create_Block ();
- //
- // Constructor
- //
- if ((modifiers & Modifiers.STATIC) == 0){
- enumerable_this_field = enumerable_proxy_class.DefineField (
- "THIS", container.TypeBuilder, FieldAttributes.Assembly);
+ return base.DefineNestedTypes ();
+ }
+
+
+ Field pc_field;
+ Field current_field;
+ Method dispose;
+
+ public Field this_field;
+ public Field[] parameter_fields;
+
+ void Create_Block ()
+ {
+ int first = is_static ? 0 : 1;
+
+ ArrayList args = new ArrayList ();
+ if (!is_static) {
+ Type t = this_type;
+ args.Add (new Argument (
+ new ThisParameterReference (t, 0, Location)));
}
- enumerable_parameter_fields = new FieldBuilder [parameters.Count];
- for (int i = 0; i < parameters.Count; i++){
- enumerable_parameter_fields [i] = enumerable_proxy_class.DefineField (
- String.Format ("able{0}_{1}", i, parameters.ParameterName (i)),
- parameters.ParameterType (i), FieldAttributes.Assembly);
- }
-
- enumerable_proxy_constructor = enumerable_proxy_class.DefineConstructor (
- MethodAttributes.Public | MethodAttributes.HideBySig |
- MethodAttributes.SpecialName | MethodAttributes.RTSpecialName,
- CallingConventions.HasThis, TypeManager.NoTypes);
- InternalParameters parameter_info = new InternalParameters (
- TypeManager.NoTypes, Parameters.EmptyReadOnlyParameters);
- TypeManager.RegisterMethod (enumerable_proxy_constructor, parameter_info, TypeManager.NoTypes);
-
- ILGenerator ig = enumerable_proxy_constructor.GetILGenerator ();
- ig.Emit (OpCodes.Ldarg_0);
- ig.Emit (OpCodes.Call, TypeManager.object_ctor);
- ig.Emit (OpCodes.Ret);
+ 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)));
+ }
+
+ Expression new_expr = new New (current_type, args, Location);
+
+ block.AddStatement (new NoCheckReturn (new_expr, Location));
}
- //
- // Populates the Enumerator Proxy class
- //
- void PopulateProxy ()
+ void Define_Fields ()
{
- RootContext.RegisterHelperClass (enumerator_proxy_class);
-
- Create_MoveNext ();
- Create_Reset ();
- Create_Current ();
- Create_Dispose ();
+ Location loc = Location.Null;
+
+ pc_field = new Field (
+ this, TypeManager.system_int32_expr, Modifiers.PRIVATE, "PC",
+ null, null, loc);
+ AddField (pc_field);
+
+ current_field = new Field (
+ this, iterator_type_expr, Modifiers.PRIVATE, "current",
+ null, null, loc);
+ AddField (current_field);
+
+ if (!is_static) {
+ this_field = new Field (
+ this, new TypeExpression (this_type, loc),
+ Modifiers.PRIVATE, "this", null, null, loc);
+ AddField (this_field);
+ }
- if (IsIEnumerable (return_type)){
- Create_GetEnumerator ();
- RootContext.RegisterHelperClass (enumerable_proxy_class);
+ parameter_fields = new Field [parameters.Count];
+ for (int i = 0; i < parameters.Count; i++) {
+ string fname = String.Format (
+ "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]);
}
}
-
- //
- // This is invoked by the EmitCode hook
- //
- void SetupIterator ()
+ void Define_Constructor ()
+ {
+ Parameters ctor_params;
+
+ ArrayList list = new ArrayList ();
+
+ if (!is_static)
+ list.Add (new Parameter (
+ new TypeExpression (this_type, Location),
+ "this", Parameter.Modifier.NONE, null));
+ list.Add (new Parameter (
+ TypeManager.system_boolean_expr, "initialized",
+ Parameter.Modifier.NONE, null));
+
+ Parameter[] old_fixed = parameters.Parameters.FixedParameters;
+ if (old_fixed != null)
+ list.AddRange (old_fixed);
+
+ 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,
+ new ConstructorBaseInitializer (
+ null, Parameters.EmptyReadOnlyParameters, Location),
+ Location);
+ AddConstructor (ctor);
+
+ ToplevelBlock block = ctor.Block = new ToplevelBlock (Location);
+
+ if (!is_static) {
+ Type t = this_type;
+
+ Assign assign = new Assign (
+ new FieldExpression (this_field),
+ new SimpleParameterReference (t, 1, Location),
+ Location);
+
+ block.AddStatement (new StatementExpression (assign, Location));
+ }
+
+ int first = is_static ? 2 : 3;
+
+ for (int i = 0; i < parameters.Count; i++) {
+ Type t = parameters.ParameterType (i);
+
+ Assign assign = new Assign (
+ new FieldExpression (parameter_fields [i]),
+ new SimpleParameterReference (t, first + i, Location),
+ Location);
+
+ 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 ()
{
- PopulateProxy ();
+ TypeExpr ex_type = new TypeExpression (
+ TypeManager.invalid_operation_exception_type, Location);
+
+ return new Throw (new New (ex_type, null, Location), Location);
}
- //
- // Our constructor
- //
- public IteratorHandler (string name, TypeContainer container, Type return_type, Type [] param_types,
- InternalParameters parameters, int modifiers, Location loc)
+ Statement Create_ThrowNotSupported ()
{
- this.name = name;
- this.container = container;
- this.return_type = return_type;
- this.param_types = param_types;
- this.parameters = parameters;
- this.modifiers = modifiers;
- this.loc = loc;
+ TypeExpr ex_type = new TypeExpression (
+ TypeManager.not_supported_exception_type, Location);
- IteratorType = TypeManager.object_type;
-
- RootContext.EmitCodeHook += new RootContext.Hook (SetupIterator);
+ return new Throw (new New (ex_type, null, Location), Location);
}
- //
- // This class is just an expression that evaluates to a type, and the
- // type is our internal proxy class. Used in the generated new body
- // of the original method
- //
- class NewInnerType : Expression {
- IteratorHandler handler;
-
- public NewInnerType (IteratorHandler handler, Location l)
+ 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);
+
+ ToplevelBlock get_block = new ToplevelBlock (Location);
+
+ get_block.AddStatement (new If (
+ new Binary (
+ Binary.Operator.LessThanOrEqual,
+ new FieldExpression (pc_field),
+ new IntLiteral ((int) State.Running), Location),
+ Create_ThrowInvalidOperation (),
+ new Return (
+ new FieldExpression (current_field), Location),
+ Location));
+
+ Accessor getter = new Accessor (get_block, 0, null, Location);
+
+ Property current = new Property (
+ this, type, 0, false, name, null, getter, null, Location);
+ AddProperty (current);
+ }
+
+ void Define_MoveNext ()
+ {
+ Method move_next = new Method (
+ this, null, TypeManager.system_boolean_expr,
+ Modifiers.PUBLIC, false, new MemberName ("MoveNext"),
+ Parameters.EmptyReadOnlyParameters, null,
+ Location.Null);
+ AddMethod (move_next);
+
+ ToplevelBlock block = move_next.Block = new ToplevelBlock (Location);
+
+ MoveNextMethod inline = new MoveNextMethod (this, Location);
+ block.AddStatement (inline);
+ }
+
+ 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, null, type, 0, false, name,
+ Parameters.EmptyReadOnlyParameters, null,
+ Location.Null);
+ AddMethod (get_enumerator);
+
+ get_enumerator.Block = new ToplevelBlock (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 (current_type, args, Location);
+ get_enumerator.Block.AddStatement (new Return (new_expr, Location));
+ }
+
+ protected class SimpleParameterReference : Expression
+ {
+ int idx;
+
+ public SimpleParameterReference (Type type, int idx, Location loc)
{
- this.handler = handler;
- eclass = ExprClass.Value;
- loc = l;
+ this.idx = idx;
+ this.loc = loc;
+ this.type = type;
+ eclass = ExprClass.Variable;
}
public override Expression DoResolve (EmitContext ec)
{
- // Create the proxy class type.
- handler.MakeEnumeratorProxy ();
+ return this;
+ }
- if (IsIEnumerable (handler.return_type))
- handler.MakeEnumerableProxy ();
+ public override void Emit (EmitContext ec)
+ {
+ DoEmit (ec);
+ }
- type = handler.return_type;
- return this;
+ 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)
+ { }
- public override Expression ResolveAsTypeStep (EmitContext ec)
+ 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;
+
+ public FieldExpression (Field field)
+ {
+ this.field = field;
+ }
+
+ public override Expression DoResolveLValue (EmitContext ec, Expression right_side)
{
return DoResolve (ec);
}
+ public override Expression DoResolve (EmitContext ec)
+ {
+ FieldExpr fexpr = new FieldExpr (field.FieldBuilder, loc);
+ fexpr.InstanceExpression = ec.GetThis (loc);
+ return fexpr.Resolve (ec);
+ }
+
public override void Emit (EmitContext ec)
{
- ILGenerator ig = ec.ig;
- FieldBuilder this_field = null;
- bool is_ienumerable = IsIEnumerable (handler.return_type);
- Type temp_type;
-
- if (is_ienumerable){
- temp_type = handler.enumerable_proxy_class;
- ig.Emit (OpCodes.Newobj, (ConstructorInfo) handler.enumerable_proxy_constructor);
- this_field = handler.enumerable_this_field;
- } else {
- temp_type = handler.enumerator_proxy_class;
- ig.Emit (OpCodes.Newobj, (ConstructorInfo) handler.enumerator_proxy_constructor);
- this_field = handler.this_field;
- }
+ throw new InvalidOperationException ();
+ }
+ }
- if (this_field == null && handler.parameters.Count == 0)
- return;
-
- LocalBuilder temp = ec.GetTemporaryLocal (temp_type);
-
- ig.Emit (OpCodes.Stloc, temp);
- //
- // Initialize This
- //
- int first = 0;
- if (this_field != null){
- ig.Emit (OpCodes.Ldloc, temp);
- ig.Emit (OpCodes.Ldarg_0);
- if (handler.container is Struct)
- ig.Emit (OpCodes.Ldobj, handler.container.TypeBuilder);
- ig.Emit (OpCodes.Stfld, this_field);
- first = 1;
- }
+ protected class MoveNextMethod : Statement {
+ Iterator iterator;
+
+ public MoveNextMethod (Iterator iterator, Location loc)
+ {
+ this.loc = loc;
+ this.iterator = iterator;
+ }
+
+ public override bool Resolve (EmitContext ec)
+ {
+ ec.CurrentBranching.CurrentUsageVector.Return ();
+ return true;
+ }
+
+ protected override void DoEmit (EmitContext ec)
+ {
+ int code_flags = Modifiers.METHOD_YIELDS;
+ if (iterator.is_static)
+ code_flags |= Modifiers.STATIC;
+
+ EmitContext new_ec = new EmitContext (
+ iterator.container, loc, ec.ig,
+ TypeManager.int32_type, code_flags);
+
+ new_ec.CurrentIterator = iterator;
+
+ iterator.EmitMoveNext (new_ec);
+ }
+ }
- for (int i = 0; i < handler.parameters.Count; i++){
- ig.Emit (OpCodes.Ldloc, temp);
- ParameterReference.EmitLdArg (ig, i + first);
- if (is_ienumerable)
- ig.Emit (OpCodes.Stfld, handler.enumerable_parameter_fields [i]);
- else
- ig.Emit (OpCodes.Stfld, handler.parameter_fields [i]);
+ 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;
}
-
- //
- // Initialize fields
- //
- ig.Emit (OpCodes.Ldloc, temp);
- ec.FreeTemporaryLocal (temp, handler.container.TypeBuilder);
+
+ return true;
}
+
+ protected override void DoEmit (EmitContext ec)
+ {
+ foreach (Statement stmt in statements)
+ stmt.Emit (ec);
+ }
+ }
+
+ protected class SetState : Statement
+ {
+ Iterator iterator;
+ State state;
+
+ public SetState (Iterator iterator, State state, Location loc)
+ {
+ this.iterator = iterator;
+ this.state = state;
+ this.loc = loc;
+ }
+
+ public override bool Resolve (EmitContext ec)
+ {
+ return true;
+ }
+
+ protected override void DoEmit (EmitContext ec)
+ {
+ 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, null, TypeManager.system_void_expr, Modifiers.PUBLIC,
+ false, new MemberName ("Reset"),
+ Parameters.EmptyReadOnlyParameters, null, Location);
+ AddMethod (reset);
+
+ reset.Block = new ToplevelBlock (Location);
+ reset.Block.AddStatement (Create_ThrowNotSupported ());
+ }
+
+ void Define_Dispose ()
+ {
+ dispose = new Method (
+ this, null, TypeManager.system_void_expr, Modifiers.PUBLIC,
+ false, new MemberName ("Dispose"),
+ Parameters.EmptyReadOnlyParameters, null, Location);
+ AddMethod (dispose);
+
+ dispose.Block = new ToplevelBlock (Location);
+ dispose.Block.AddStatement (new DisposeMethod (this, Location));
+ }
+
+ public ToplevelBlock Block {
+ get { return block; }
+ }
+
+ public Type IteratorType {
+ get { return iterator_type; }
}
//
public NoCheckReturn (Expression expr, Location loc) : base (expr, loc)
{
}
-
+
public override bool Resolve (EmitContext ec)
{
ec.InIterator = false;
}
}
- static bool IsIEnumerable (Type t)
- {
- return t == TypeManager.ienumerable_type || TypeManager.ImplementsInterface (t, TypeManager.ienumerable_type);
- }
-
- static bool IsIEnumerator (Type t)
- {
- return t == TypeManager.ienumerator_type || TypeManager.ImplementsInterface (t, TypeManager.ienumerator_type);
- }
-
- //
- // Returns the new block for the method, or null on failure
- //
- public Block Setup (Block block)
+ bool CheckType (Type t)
{
- if (!(IsIEnumerator (return_type) || IsIEnumerable (return_type))){
- Report.Error (
- -205, loc, String.Format (
- "The method `{0}' contains a yield statement, but has an invalid return type for an iterator `{1}'",
- name, TypeManager.CSharpName (return_type)));
- return null;
+ if (t == TypeManager.ienumerable_type) {
+ iterator_type = TypeManager.object_type;
+ is_enumerable = true;
+ return true;
+ } else if (t == TypeManager.ienumerator_type) {
+ iterator_type = TypeManager.object_type;
+ is_enumerable = false;
+ return true;
}
- for (int i = 0; i < parameters.Count; i++){
- Parameter.Modifier mod = parameters.ParameterModifier (i);
- if ((mod & (Parameter.Modifier.REF | Parameter.Modifier.OUT)) != 0){
- Report.Error (-207, loc, String.Format (
- "Parameter {0} of `{1}' is {2} and not allowed for an iterator method",
- i+1, name, parameters.ParameterDesc (i)));
- return null;
- }
- }
+ if (!t.IsGenericInstance)
+ return false;
- original_block = block;
- Block b = new Block (null);
+ 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 new InnerClass ()
- b.AddStatement (new NoCheckReturn (new NewInnerType (this, loc), loc));
- return b;
+ return false;
}
}
}