X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fgmcs%2Fexpression.cs;h=889d3eba69703e357e38bd15c0fb18a984ce0a12;hb=dd866d68820e0f66046256bb5d3f84e3988a8be0;hp=0360942d00c94b2a1c00671176054486fbac9c1e;hpb=27f8787c6c858eb8d6c86ed0e59b7fc6d995192c;p=mono.git diff --git a/mcs/gmcs/expression.cs b/mcs/gmcs/expression.cs index 0360942d00c..889d3eba697 100755 --- a/mcs/gmcs/expression.cs +++ b/mcs/gmcs/expression.cs @@ -46,13 +46,13 @@ namespace Mono.CSharp { public override void Emit (EmitContext ec) { if (args != null) - Invocation.EmitArguments (ec, mi, args, false, null); + Invocation.EmitArguments (ec, mi, args); ec.ig.Emit (OpCodes.Call, mi); return; } - static public StaticCallExpr MakeSimpleCall (EmitContext ec, MethodGroupExpr mg, + static public Expression MakeSimpleCall (EmitContext ec, MethodGroupExpr mg, Expression e, Location loc) { ArrayList args; @@ -81,10 +81,6 @@ namespace Mono.CSharp { if (TypeManager.TypeToCoreType (type) != TypeManager.void_type) ec.ig.Emit (OpCodes.Pop); } - - public MethodInfo Method { - get { return mi; } - } } public class ParenthesizedExpression : Expression @@ -648,7 +644,7 @@ namespace Mono.CSharp { public class Indirection : Expression, IMemoryLocation, IAssignMethod { Expression expr; LocalTemporary temporary; - bool prepared; + bool have_temporary; public Indirection (Expression expr, Location l) { @@ -664,47 +660,54 @@ namespace Mono.CSharp { public override void Emit (EmitContext ec) { - if (!prepared) - expr.Emit (ec); - - LoadFromPtr (ec.ig, Type); - } + ILGenerator ig = ec.ig; - public void Emit (EmitContext ec, bool leave_copy) - { - Emit (ec); - if (leave_copy) { + if (temporary != null){ + if (have_temporary) { + temporary.Emit (ec); + } else { + expr.Emit (ec); ec.ig.Emit (OpCodes.Dup); - temporary = new LocalTemporary (ec, expr.Type); temporary.Store (ec); - } + have_temporary = true; + } + } else + expr.Emit (ec); + + LoadFromPtr (ig, Type); } - public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load) + public void EmitAssign (EmitContext ec, Expression source) { - prepared = prepare_for_load; - - expr.Emit (ec); - - if (prepare_for_load) - ec.ig.Emit (OpCodes.Dup); + if (temporary != null){ + if (have_temporary) + temporary.Emit (ec); + else { + expr.Emit (ec); + ec.ig.Emit (OpCodes.Dup); + temporary.Store (ec); + have_temporary = true; + } + } else + expr.Emit (ec); source.Emit (ec); - if (leave_copy) { - ec.ig.Emit (OpCodes.Dup); - temporary = new LocalTemporary (ec, expr.Type); - temporary.Store (ec); - } - StoreFromPtr (ec.ig, type); - - if (temporary != null) - temporary.Emit (ec); } - + public void AddressOf (EmitContext ec, AddressOp Mode) { - expr.Emit (ec); + if (temporary != null){ + if (have_temporary){ + temporary.Emit (ec); + return; + } + expr.Emit (ec); + ec.ig.Emit (OpCodes.Dup); + temporary.Store (ec); + have_temporary = true; + } else + expr.Emit (ec); } public override Expression DoResolve (EmitContext ec) @@ -714,7 +717,12 @@ namespace Mono.CSharp { // return this; } - + + public new void CacheTemporaries (EmitContext ec) + { + temporary = new LocalTemporary (ec, expr.Type); + } + public override string ToString () { return "*(" + expr + ")"; @@ -750,15 +758,13 @@ namespace Mono.CSharp { } Mode mode; - bool is_expr = false; - bool recurse = false; - Expression expr; + LocalTemporary temp_storage; // // This is expensive for the simplest case. // - StaticCallExpr method; + Expression method; public UnaryMutator (Mode m, Expression e, Location l) { @@ -850,7 +856,9 @@ namespace Mono.CSharp { } else if (expr.eclass == ExprClass.IndexerAccess){ IndexerAccess ia = (IndexerAccess) expr; - expr = ia.ResolveLValue (ec, this); + temp_storage = new LocalTemporary (ec, expr.Type); + + expr = ia.ResolveLValue (ec, temp_storage); if (expr == null) return null; @@ -968,39 +976,114 @@ namespace Mono.CSharp { } } + + static EmptyExpression empty_expr; void EmitCode (EmitContext ec, bool is_expr) { - recurse = true; - this.is_expr = is_expr; - ((IAssignMethod) expr).EmitAssign (ec, this, is_expr && (mode == Mode.PreIncrement || mode == Mode.PreDecrement), true); - } - + ILGenerator ig = ec.ig; + IAssignMethod ia = (IAssignMethod) expr; + Type expr_type = expr.Type; + + ia.CacheTemporaries (ec); - public override void Emit (EmitContext ec) - { // - // We use recurse to allow ourselfs to be the source - // of an assignment. This little hack prevents us from - // having to allocate another expression + // NOTE: We should probably handle three cases: // - if (recurse) { - ((IAssignMethod) expr).Emit (ec, is_expr && (mode == Mode.PostIncrement || mode == Mode.PostDecrement)); - if (method == null) - LoadOneAndEmitOp (ec, expr.Type); - else - ec.ig.Emit (OpCodes.Call, method.Method); - recurse = false; - return; + // * method invocation required. + // * direct stack manipulation possible + // * the object requires an "instance" field + // + if (temp_storage == null){ + // + // Temporary improvement: if we are dealing with something that does + // not require complicated instance setup, avoid using a temporary + // + // For now: only localvariables when not remapped + // + + if (method == null && + ((expr is LocalVariableReference) ||(expr is FieldExpr && ((FieldExpr) expr).FieldInfo.IsStatic))){ + if (empty_expr == null) + empty_expr = new EmptyExpression (); + + switch (mode){ + case Mode.PreIncrement: + case Mode.PreDecrement: + expr.Emit (ec); + + LoadOneAndEmitOp (ec, expr_type); + if (is_expr) + ig.Emit (OpCodes.Dup); + ia.EmitAssign (ec, empty_expr); + break; + + case Mode.PostIncrement: + case Mode.PostDecrement: + expr.Emit (ec); + if (is_expr) + ig.Emit (OpCodes.Dup); + + LoadOneAndEmitOp (ec, expr_type); + ia.EmitAssign (ec, empty_expr); + break; + } + return; + } + temp_storage = new LocalTemporary (ec, expr_type); } + switch (mode){ + case Mode.PreIncrement: + case Mode.PreDecrement: + if (method == null){ + expr.Emit (ec); + + LoadOneAndEmitOp (ec, expr_type); + } else + method.Emit (ec); + + temp_storage.Store (ec); + ia.EmitAssign (ec, temp_storage); + if (is_expr) + temp_storage.Emit (ec); + break; + + case Mode.PostIncrement: + case Mode.PostDecrement: + if (is_expr) + expr.Emit (ec); + + if (method == null){ + if (!is_expr) + expr.Emit (ec); + else + ig.Emit (OpCodes.Dup); + + LoadOneAndEmitOp (ec, expr_type); + } else { + method.Emit (ec); + } + + temp_storage.Store (ec); + ia.EmitAssign (ec, temp_storage); + break; + } + + temp_storage.Release (ec); + } + + public override void Emit (EmitContext ec) + { EmitCode (ec, true); + } public override void EmitStatement (EmitContext ec) { EmitCode (ec, false); } + } /// @@ -2056,10 +2139,6 @@ namespace Mono.CSharp { (other == TypeManager.int32_type) || (other == TypeManager.int64_type)) Error_OperatorAmbiguous (loc, oper, l, r); - else { - left = ForceConversion (ec, left, TypeManager.uint64_type); - right = ForceConversion (ec, right, TypeManager.uint64_type); - } type = TypeManager.uint64_type; } else if (IsOfType (ec, l, r, TypeManager.int64_type, check_user_conv)){ // @@ -3084,7 +3163,7 @@ namespace Mono.CSharp { ILGenerator ig = ec.ig; if (Arguments != null) - Invocation.EmitArguments (ec, method, Arguments, false, null); + Invocation.EmitArguments (ec, method, Arguments); if (method is MethodInfo) ig.Emit (OpCodes.Call, (MethodInfo) method); @@ -3219,7 +3298,7 @@ namespace Mono.CSharp { break; } - Invocation.EmitArguments (ec, concat_method, operands, false, null); + Invocation.EmitArguments (ec, concat_method, operands); ec.ig.Emit (OpCodes.Call, concat_method); } } @@ -3248,7 +3327,7 @@ namespace Mono.CSharp { { ILGenerator ig = ec.ig; - Invocation.EmitArguments (ec, method, args, false, null); + Invocation.EmitArguments (ec, method, args); ig.Emit (OpCodes.Call, (MethodInfo) method); ig.Emit (OpCodes.Castclass, type); @@ -3616,7 +3695,7 @@ namespace Mono.CSharp { if (e != null) { local_info.Used = true; eclass = ExprClass.Value; - return e.Resolve (ec); + return e; } VariableInfo variable_info = local_info.VariableInfo; @@ -3677,19 +3756,12 @@ namespace Mono.CSharp { ig.Emit (OpCodes.Ldloc, local_info.LocalBuilder); } - public void Emit (EmitContext ec, bool leave_copy) - { - Emit (ec); - if (leave_copy) - ec.ig.Emit (OpCodes.Dup); - } - - public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load) + public void EmitAssign (EmitContext ec, Expression source) { + ILGenerator ig = ec.ig; + source.Emit (ec); - if (leave_copy) - ec.ig.Emit (OpCodes.Dup); - ec.ig.Emit (OpCodes.Stloc, local_info.LocalBuilder); + ig.Emit (OpCodes.Stloc, local_info.LocalBuilder); } public void AddressOf (EmitContext ec, AddressOp mode) @@ -3716,8 +3788,7 @@ namespace Mono.CSharp { Block block; VariableInfo vi; public Parameter.Modifier mod; - public bool is_ref, is_out, prepared; - LocalTemporary temp; + public bool is_ref, is_out; public ParameterReference (Parameters pars, Block block, int idx, string name, Location loc) { @@ -3852,11 +3923,6 @@ namespace Mono.CSharp { } public override void Emit (EmitContext ec) - { - Emit (ec, false); - } - - public void Emit (EmitContext ec, bool leave_copy) { ILGenerator ig = ec.ig; @@ -3867,56 +3933,33 @@ namespace Mono.CSharp { EmitLdArg (ig, arg_idx); - if (is_ref) { - if (prepared) - ec.ig.Emit (OpCodes.Dup); - - // - // If we are a reference, we loaded on the stack a pointer - // Now lets load the real value - // - LoadFromPtr (ig, type); - } - - if (leave_copy) { - ec.ig.Emit (OpCodes.Dup); - - if (is_ref) { - temp = new LocalTemporary (ec, type); - temp.Store (ec); - } - } + if (!is_ref) + return; + + // + // If we are a reference, we loaded on the stack a pointer + // Now lets load the real value + // + LoadFromPtr (ig, type); } - - public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load) + + public void EmitAssign (EmitContext ec, Expression source) { ILGenerator ig = ec.ig; - int arg_idx = idx; - - prepared = prepare_for_load; + int arg_idx = idx; + if (!ec.IsStatic) arg_idx++; - if (is_ref && !prepared) + if (is_ref) EmitLdArg (ig, arg_idx); source.Emit (ec); - if (leave_copy) - ec.ig.Emit (OpCodes.Dup); - - if (is_ref) { - if (leave_copy) { - temp = new LocalTemporary (ec, type); - temp.Store (ec); - } - + if (is_ref) StoreFromPtr (ig, type); - - if (temp != null) - temp.Emit (ec); - } else { + else { if (arg_idx <= 255) ig.Emit (OpCodes.Starg_S, (byte) arg_idx); else @@ -3966,12 +4009,6 @@ namespace Mono.CSharp { this.ArgType = type; } - public Argument (Expression expr) - { - this.Expr = expr; - this.ArgType = AType.Expression; - } - public Type Type { get { if (ArgType == AType.Ref || ArgType == AType.Out) @@ -4179,12 +4216,9 @@ namespace Mono.CSharp { /// static int BetterConversion (EmitContext ec, Argument a, Type p, Type q, Location loc) { - Type argument_type = TypeManager.TypeToCoreType (a.Type); + Type argument_type = a.Type; Expression argument_expr = a.Expr; - // p = TypeManager.TypeToCoreType (p); - // q = TypeManager.TypeToCoreType (q); - if (argument_type == null) throw new Exception ("Expression of type " + a.Expr + " does not resolve its type"); @@ -4229,6 +4263,85 @@ namespace Mono.CSharp { if (argument_type == q) return 0; + // + // Now probe whether an implicit constant expression conversion + // can be used. + // + // An implicit constant expression conversion permits the following + // conversions: + // + // * A constant-expression of type `int' can be converted to type + // sbyte, byute, short, ushort, uint, ulong provided the value of + // of the expression is withing the range of the destination type. + // + // * A constant-expression of type long can be converted to type + // ulong, provided the value of the constant expression is not negative + // + // FIXME: Note that this assumes that constant folding has + // taken place. We dont do constant folding yet. + // + + if (argument_expr is IntConstant){ + IntConstant ei = (IntConstant) argument_expr; + int value = ei.Value; + + if (p == TypeManager.sbyte_type){ + if (value >= SByte.MinValue && value <= SByte.MaxValue) + return 1; + } else if (p == TypeManager.byte_type){ + if (q == TypeManager.sbyte_type && + value >= SByte.MinValue && value <= SByte.MaxValue) + return 0; + else if (Byte.MinValue >= 0 && value <= Byte.MaxValue) + return 1; + } else if (p == TypeManager.short_type){ + if (value >= Int16.MinValue && value <= Int16.MaxValue) + return 1; + } else if (p == TypeManager.ushort_type){ + if (q == TypeManager.short_type && + value >= Int16.MinValue && value <= Int16.MaxValue) + return 0; + else if (value >= UInt16.MinValue && value <= UInt16.MaxValue) + return 1; + } else if (p == TypeManager.int32_type){ + if (value >= Int32.MinValue && value <= Int32.MaxValue) + return 1; + } else if (p == TypeManager.uint32_type){ + // + // we can optimize this case: a positive int32 + // always fits on a uint32 + // + if (value >= 0) + return 1; + } else if (p == TypeManager.uint64_type){ + // + // we can optimize this case: a positive int32 + // always fits on a uint64 + // + + // + // This special case is needed because csc behaves like this. + // int -> uint is better than int -> ulong! + // + if (q == TypeManager.uint32_type) + return 0; + + if (q == TypeManager.int64_type) + return 0; + else if (value >= 0) + return 1; + } else if (p == TypeManager.int64_type){ + return 1; + } + } else if (argument_type == TypeManager.int64_type && argument_expr is LongConstant){ + LongConstant lc = (LongConstant) argument_expr; + + if (p == TypeManager.uint64_type){ + if (lc.Value > 0) + return 1; + } + } + if (q == null) { Expression tmp = Convert.ImplicitConversion (ec, argument_expr, p, loc); @@ -4275,7 +4388,7 @@ namespace Mono.CSharp { /// 0 if candidate ain't better /// 1 if candidate is better than the current best match /// - static int BetterFunction (EmitContext ec, MethodGroupExpr me, ArrayList args, + static int BetterFunction (EmitContext ec, ArrayList args, MethodBase candidate, bool candidate_params, MethodBase best, bool best_params, Location loc) @@ -4330,8 +4443,7 @@ namespace Mono.CSharp { for (int j = 0; j < argument_count; ++j) { Argument a = (Argument) args [j]; - Type t = TypeManager.TypeToCoreType ( - candidate_pd.ParameterType (j)); + Type t = candidate_pd.ParameterType (j); if (candidate_pd.ParameterModifier (j) == Parameter.Modifier.PARAMS) if (candidate_params) @@ -4352,16 +4464,14 @@ namespace Mono.CSharp { best_pd = GetParameterData (best); int rating1 = 0, rating2 = 0; - + for (int j = 0; j < argument_count; ++j) { int x, y; Argument a = (Argument) args [j]; - Type ct = TypeManager.TypeToCoreType ( - candidate_pd.ParameterType (j)); - Type bt = TypeManager.TypeToCoreType ( - best_pd.ParameterType (j)); + Type ct = candidate_pd.ParameterType (j); + Type bt = best_pd.ParameterType (j); if (candidate_pd.ParameterModifier (j) == Parameter.Modifier.PARAMS) if (candidate_params) @@ -4755,7 +4865,7 @@ namespace Mono.CSharp { if (method != null) method_params = (bool) candidate_to_form [method]; - int x = BetterFunction (ec, me, Arguments, + int x = BetterFunction (ec, Arguments, candidate, cand_params, method, method_params, loc); @@ -4849,7 +4959,7 @@ namespace Mono.CSharp { // continue; bool cand_params = (bool) candidate_to_form [candidate]; - int x = BetterFunction (ec, me, Arguments, + int x = BetterFunction (ec, Arguments, method, best_params, candidate, cand_params, loc); @@ -5360,24 +5470,14 @@ namespace Mono.CSharp { /// emission of the arguments is known not to contain /// a `params' field (for example in constructors or other routines /// that keep their arguments in this structure) - /// - /// if `dup_args' is true, a copy of the arguments will be left - /// on the stack. If `dup_args' is true, you can specify `this_arg' - /// which will be duplicated before any other args. Only EmitCall - /// should be using this interface. /// - public static void EmitArguments (EmitContext ec, MethodBase mb, ArrayList arguments, bool dup_args, LocalTemporary this_arg) + public static void EmitArguments (EmitContext ec, MethodBase mb, ArrayList arguments) { ParameterData pd; if (mb != null) pd = GetParameterData (mb); else pd = null; - - LocalTemporary [] temps = null; - - if (dup_args) - temps = new LocalTemporary [arguments.Count]; // // If we are calling a params method with no arguments, special case it @@ -5414,18 +5514,6 @@ namespace Mono.CSharp { } a.Emit (ec); - if (dup_args) { - ec.ig.Emit (OpCodes.Dup); - (temps [i] = new LocalTemporary (ec, a.Type)).Store (ec); - } - } - - if (dup_args) { - if (this_arg != null) - this_arg.Emit (ec); - - for (int i = 0; i < top; i ++) - temps [i].Emit (ec); } if (pd != null && pd.Count > top && @@ -5489,25 +5577,10 @@ namespace Mono.CSharp { public static void EmitCall (EmitContext ec, bool is_base, bool is_static, Expression instance_expr, MethodBase method, ArrayList Arguments, Location loc) - { - EmitCall (ec, is_base, is_static, instance_expr, method, Arguments, loc, false, false); - } - - // `dup_args' leaves an extra copy of the arguments on the stack - // `omit_args' does not leave any arguments at all. - // So, basically, you could make one call with `dup_args' set to true, - // and then another with `omit_args' set to true, and the two calls - // would have the same set of arguments. However, each argument would - // only have been evaluated once. - public static void EmitCall (EmitContext ec, bool is_base, - bool is_static, Expression instance_expr, - MethodBase method, ArrayList Arguments, Location loc, - bool dup_args, bool omit_args) { ILGenerator ig = ec.ig; bool struct_call = false; bool this_call = false; - LocalTemporary this_arg = null; Type decl_type = method.DeclaringType; @@ -5552,69 +5625,57 @@ namespace Mono.CSharp { return; if (!is_static){ - this_call = instance_expr == null; - if (decl_type.IsValueType || (!this_call && instance_expr.Type.IsValueType)) + if (TypeManager.IsValueType (decl_type)) struct_call = true; - // // If this is ourselves, push "this" // - if (!omit_args) { - Type t = null; - if (this_call) { - ig.Emit (OpCodes.Ldarg_0); - t = decl_type; - } else { - // - // Push the instance expression + if (instance_expr == null){ + this_call = true; + ig.Emit (OpCodes.Ldarg_0); + } else { + Type itype = instance_expr.Type; + + // + // Push the instance expression + // + if (TypeManager.IsValueType (itype)){ // - if (instance_expr.Type.IsValueType) { + // Special case: calls to a function declared in a + // reference-type with a value-type argument need + // to have their value boxed. + if (decl_type.IsValueType || itype.IsGenericParameter){ // - // Special case: calls to a function declared in a - // reference-type with a value-type argument need - // to have their value boxed. - if (decl_type.IsValueType) { - // - // If the expression implements IMemoryLocation, then - // we can optimize and use AddressOf on the - // return. - // - // If not we have to use some temporary storage for - // it. - if (instance_expr is IMemoryLocation) { - ((IMemoryLocation)instance_expr). - AddressOf (ec, AddressOp.LoadStore); - } else { - LocalTemporary temp = new LocalTemporary (ec, instance_expr.Type); - instance_expr.Emit (ec); - temp.Store (ec); - temp.AddressOf (ec, AddressOp.Load); - } - - // avoid the overhead of doing this all the time. - if (dup_args) - t = TypeManager.GetReferenceType (instance_expr.Type); - } else { + // If the expression implements IMemoryLocation, then + // we can optimize and use AddressOf on the + // return. + // + // If not we have to use some temporary storage for + // it. + if (instance_expr is IMemoryLocation){ + ((IMemoryLocation)instance_expr). + AddressOf (ec, AddressOp.LoadStore); + } + else { instance_expr.Emit (ec); - ig.Emit (OpCodes.Box, instance_expr.Type); - t = TypeManager.object_type; + LocalBuilder temp = ig.DeclareLocal (itype); + ig.Emit (OpCodes.Stloc, temp); + ig.Emit (OpCodes.Ldloca, temp); } + if (itype.IsGenericParameter) + ig.Emit (OpCodes.Constrained, itype); + else + struct_call = true; } else { instance_expr.Emit (ec); - t = instance_expr.Type; - } - } - - if (dup_args) { - this_arg = new LocalTemporary (ec, t); - ig.Emit (OpCodes.Dup); - this_arg.Store (ec); - } + ig.Emit (OpCodes.Box, itype); + } + } else + instance_expr.Emit (ec); } } - if (!omit_args) - EmitArguments (ec, method, Arguments, dup_args, this_arg); + EmitArguments (ec, method, Arguments); OpCode call_op; if (is_static || struct_call || is_base || (this_call && !method.IsVirtual)) @@ -5634,9 +5695,9 @@ namespace Mono.CSharp { // and DoFoo is not virtual, you can omit the callvirt, // because you don't need the null checking behavior. // - if (method is MethodInfo) + if (method is MethodInfo) ig.Emit (call_op, (MethodInfo) method); - else + else ig.Emit (call_op, (ConstructorInfo) method); } @@ -6011,7 +6072,7 @@ namespace Mono.CSharp { } if (method != null) - Invocation.EmitArguments (ec, method, Arguments, false, null); + Invocation.EmitArguments (ec, method, Arguments); if (is_value_type){ if (method == null) @@ -6067,7 +6128,7 @@ namespace Mono.CSharp { IMemoryLocation ml = (IMemoryLocation) value_target; ml.AddressOf (ec, AddressOp.Store); if (method != null) - Invocation.EmitArguments (ec, method, Arguments, false, null); + Invocation.EmitArguments (ec, method, Arguments); if (method == null) ec.ig.Emit (OpCodes.Initobj, type); @@ -6751,18 +6812,12 @@ namespace Mono.CSharp { e.Emit (ec); - if (dims == 1) { - bool is_stobj, has_typearg; - OpCode op = ArrayAccess.GetStoreOpcode ( - etype, out is_stobj, - out has_typearg); - if (is_stobj) - ig.Emit (OpCodes.Stobj, etype); - else - ig.Emit (op); - } else + if (dims == 1) + ArrayAccess.EmitStoreOpcode (ig, array_element_type); + else ig.Emit (OpCodes.Call, set); - } + + } } // @@ -6950,36 +7005,28 @@ namespace Mono.CSharp { return this; } - public void Emit (EmitContext ec, bool leave_copy) + public override void Emit (EmitContext ec) { - Emit (ec); - if (leave_copy) - ec.ig.Emit (OpCodes.Dup); + ILGenerator ig = ec.ig; + + ec.EmitThis (); + if (ec.TypeContainer is Struct) + ig.Emit (OpCodes.Ldobj, type); } - - public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load) + + public void EmitAssign (EmitContext ec, Expression source) { ILGenerator ig = ec.ig; if (ec.TypeContainer is Struct){ ec.EmitThis (); source.Emit (ec); - if (leave_copy) - ec.ig.Emit (OpCodes.Dup); ig.Emit (OpCodes.Stobj, type); } else { - throw new Exception ("how did you get here"); + source.Emit (ec); + ig.Emit (OpCodes.Starg, 0); } } - - public override void Emit (EmitContext ec) - { - ILGenerator ig = ec.ig; - - ec.EmitThis (); - if (ec.TypeContainer is Struct) - ig.Emit (OpCodes.Ldobj, type); - } public void AddressOf (EmitContext ec, AddressOp mode) { @@ -7537,7 +7584,7 @@ namespace Mono.CSharp { member_lookup = MemberLookup ( ec, expr_type, expr_type, Identifier, loc); if ((member_lookup == null) && (args != null)) { - string lookup_id = MemberName.MakeName (Identifier, args); + string lookup_id = Identifier + "!" + args.Count; member_lookup = MemberLookup ( ec, expr_type, expr_type, lookup_id, loc); } @@ -7620,8 +7667,6 @@ namespace Mono.CSharp { else fname = full_expr.Identifier; - fname = MemberName.MakeName (fname, args); - if (full_expr.Expr is SimpleName) { string full_name = String.Concat (((SimpleName) full_expr.Expr).Name, ".", fname); Type fully_qualified = ec.DeclSpace.FindType (loc, full_name); @@ -7655,7 +7700,10 @@ namespace Mono.CSharp { Expression member_lookup; string lookup_id; - lookup_id = MemberName.MakeName (Identifier, args); + if (args != null) + lookup_id = Identifier + "!" + args.Count; + else + lookup_id = Identifier; member_lookup = MemberLookupFinal ( ec, expr_type, expr_type, lookup_id, loc); if (member_lookup == null) @@ -7697,7 +7745,10 @@ namespace Mono.CSharp { public override string ToString () { - return expr + "." + MemberName.MakeName (Identifier, args); + if (args != null) + return expr + "." + Identifier + "!" + args.Count; + else + return expr + "." + Identifier; } } @@ -7915,8 +7966,7 @@ namespace Mono.CSharp { // ElementAccess ea; - LocalTemporary temp; - bool prepared; + LocalTemporary [] cached_locations; public ArrayAccess (ElementAccess ea_data, Location l) { @@ -8017,6 +8067,20 @@ namespace Mono.CSharp { ig.Emit (OpCodes.Ldelem_Ref); } + /// + /// Emits the right opcode to store an object of Type `t' + /// from an array of T. + /// + static public void EmitStoreOpcode (ILGenerator ig, Type t) + { + bool is_stobj, has_type_arg; + OpCode op = GetStoreOpcode (t, out is_stobj, out has_type_arg); + if (has_type_arg) + ig.Emit (op, t); + else + ig.Emit (op); + } + /// /// Returns the right opcode to store an object of Type `t' /// from an array of T. @@ -8026,7 +8090,7 @@ namespace Mono.CSharp { //Console.WriteLine (new System.Diagnostics.StackTrace ()); has_type_arg = false; is_stobj = false; t = TypeManager.TypeToCoreType (t); - if (TypeManager.IsEnumType (t)) + if (TypeManager.IsEnumType (t) && t != TypeManager.enum_type) t = TypeManager.EnumToUnderlying (t); if (t == TypeManager.byte_type || t == TypeManager.sbyte_type || t == TypeManager.bool_type) @@ -8113,111 +8177,101 @@ namespace Mono.CSharp { { ILGenerator ig = ec.ig; - ea.Expr.Emit (ec); - foreach (Argument a in ea.Arguments){ - Type argtype = a.Expr.Type; + if (cached_locations == null){ + ea.Expr.Emit (ec); + foreach (Argument a in ea.Arguments){ + Type argtype = a.Expr.Type; + + a.Expr.Emit (ec); + + if (argtype == TypeManager.int64_type) + ig.Emit (OpCodes.Conv_Ovf_I); + else if (argtype == TypeManager.uint64_type) + ig.Emit (OpCodes.Conv_Ovf_I_Un); + } + return; + } + + if (cached_locations [0] == null){ + cached_locations [0] = new LocalTemporary (ec, ea.Expr.Type); + ea.Expr.Emit (ec); + ig.Emit (OpCodes.Dup); + cached_locations [0].Store (ec); - a.Expr.Emit (ec); + int j = 1; - if (argtype == TypeManager.int64_type) - ig.Emit (OpCodes.Conv_Ovf_I); - else if (argtype == TypeManager.uint64_type) - ig.Emit (OpCodes.Conv_Ovf_I_Un); + foreach (Argument a in ea.Arguments){ + Type argtype = a.Expr.Type; + + cached_locations [j] = new LocalTemporary (ec, TypeManager.intptr_type /* a.Expr.Type */); + a.Expr.Emit (ec); + if (argtype == TypeManager.int64_type) + ig.Emit (OpCodes.Conv_Ovf_I); + else if (argtype == TypeManager.uint64_type) + ig.Emit (OpCodes.Conv_Ovf_I_Un); + + ig.Emit (OpCodes.Dup); + cached_locations [j].Store (ec); + j++; + } + return; } + + foreach (LocalTemporary lt in cached_locations) + lt.Emit (ec); } - public void Emit (EmitContext ec, bool leave_copy) + public new void CacheTemporaries (EmitContext ec) + { + cached_locations = new LocalTemporary [ea.Arguments.Count + 1]; + } + + public override void Emit (EmitContext ec) { int rank = ea.Expr.Type.GetArrayRank (); ILGenerator ig = ec.ig; - if (!prepared) { - LoadArrayAndArguments (ec); - - if (rank == 1) - EmitLoadOpcode (ig, type); - else { - MethodInfo method; - - method = FetchGetMethod (); - ig.Emit (OpCodes.Call, method); - } - } else - LoadFromPtr (ec.ig, this.type); + LoadArrayAndArguments (ec); - if (leave_copy) { - ec.ig.Emit (OpCodes.Dup); - temp = new LocalTemporary (ec, this.type); - temp.Store (ec); + if (rank == 1) + EmitLoadOpcode (ig, type); + else { + MethodInfo method; + + method = FetchGetMethod (); + ig.Emit (OpCodes.Call, method); } } - - public override void Emit (EmitContext ec) - { - Emit (ec, false); - } - public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load) + public void EmitAssign (EmitContext ec, Expression source) { int rank = ea.Expr.Type.GetArrayRank (); ILGenerator ig = ec.ig; Type t = source.Type; - prepared = prepare_for_load; - if (prepare_for_load) { - AddressOf (ec, AddressOp.LoadStore); - ec.ig.Emit (OpCodes.Dup); - source.Emit (ec); - if (leave_copy) { - ec.ig.Emit (OpCodes.Dup); - temp = new LocalTemporary (ec, this.type); - temp.Store (ec); - } - StoreFromPtr (ec.ig, t); - - if (temp != null) - temp.Emit (ec); - - return; - } - LoadArrayAndArguments (ec); - if (rank == 1) { - bool is_stobj, has_type_arg; - OpCode op = GetStoreOpcode (t, out is_stobj, out has_type_arg); - // - // The stobj opcode used by value types will need - // an address on the stack, not really an array/array - // pair - // - if (is_stobj) + // + // The stobj opcode used by value types will need + // an address on the stack, not really an array/array + // pair + // + if (rank == 1){ + if (t == TypeManager.enum_type || t == TypeManager.decimal_type || + (t.IsSubclassOf (TypeManager.value_type) && !TypeManager.IsEnumType (t) && !TypeManager.IsBuiltinType (t))) ig.Emit (OpCodes.Ldelema, t); - - source.Emit (ec); - if (leave_copy) { - ec.ig.Emit (OpCodes.Dup); - temp = new LocalTemporary (ec, this.type); - temp.Store (ec); - } - - if (is_stobj) - ig.Emit (OpCodes.Stobj, t); - else - ig.Emit (op); - } else { + } + + source.Emit (ec); + + if (rank == 1) + EmitStoreOpcode (ig, t); + else { ModuleBuilder mb = CodeGen.Module.Builder; int arg_count = ea.Arguments.Count; Type [] args = new Type [arg_count + 1]; MethodInfo set; - source.Emit (ec); - if (leave_copy) { - ec.ig.Emit (OpCodes.Dup); - temp = new LocalTemporary (ec, this.type); - temp.Store (ec); - } - for (int i = 0; i < arg_count; i++){ //args [i++] = a.Type; args [i] = TypeManager.int32_type; @@ -8233,9 +8287,6 @@ namespace Mono.CSharp { ig.Emit (OpCodes.Call, set); } - - if (temp != null) - temp.Emit (ec); } public void AddressOf (EmitContext ec, AddressOp mode) @@ -8528,53 +8579,19 @@ namespace Mono.CSharp { return this; } - bool prepared = false; - LocalTemporary temp; - - public void Emit (EmitContext ec, bool leave_copy) + public override void Emit (EmitContext ec) { - Invocation.EmitCall (ec, is_base_indexer, false, instance_expr, get, arguments, loc, prepared, false); - if (leave_copy) { - ec.ig.Emit (OpCodes.Dup); - temp = new LocalTemporary (ec, Type); - temp.Store (ec); - } + Invocation.EmitCall (ec, is_base_indexer, false, instance_expr, get, arguments, loc); } - + // // source is ignored, because we already have a copy of it from the // LValue resolution and we have already constructed a pre-cached // version of the arguments (ea.set_arguments); // - public void EmitAssign (EmitContext ec, Expression source, bool leave_copy, bool prepare_for_load) + public void EmitAssign (EmitContext ec, Expression source) { - prepared = prepare_for_load; - Argument a = (Argument) set_arguments [set_arguments.Count - 1]; - - if (prepared) { - source.Emit (ec); - if (leave_copy) { - ec.ig.Emit (OpCodes.Dup); - temp = new LocalTemporary (ec, Type); - temp.Store (ec); - } - } else if (leave_copy) { - temp = new LocalTemporary (ec, Type); - source.Emit (ec); - temp.Store (ec); - a.Expr = temp; - } - - Invocation.EmitCall (ec, is_base_indexer, false, instance_expr, set, set_arguments, loc, false, prepared); - - if (temp != null) - temp.Emit (ec); - } - - - public override void Emit (EmitContext ec) - { - Emit (ec, false); + Invocation.EmitCall (ec, is_base_indexer, false, instance_expr, set, set_arguments, loc); } } @@ -8981,14 +8998,6 @@ namespace Mono.CSharp { return null; } - Constant c = count as Constant; - // TODO: because we don't have property IsNegative - if (c != null && c.ConvertToUInt () == null) { - // "Cannot use a negative size with stackalloc" - Report.Error_T (247, loc); - return null; - } - if (ec.CurrentBranching.InCatch () || ec.CurrentBranching.InFinally (true)) { Error (255,