//
public void Emit (EmitContext ec)
{
- Emit (ec, false, null);
+ Emit (ec, false);
}
//
// 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.
+ // on the stack and return value will contain an array of access
+ // expressions
+ // NOTE: It's caller responsibility is to release temporary variables
//
- public void Emit (EmitContext ec, bool dup_args, LocalTemporary this_arg)
+ public Expression[] Emit (EmitContext ec, bool dup_args)
{
- LocalTemporary[] temps = null;
+ Expression[] temps;
if (dup_args && Count != 0)
- temps = new LocalTemporary [Count];
+ temps = new Expression [Count];
+ else
+ temps = null;
if (reordered != null && Count > 1) {
foreach (NamedArgument na in reordered)
}
int i = 0;
+ LocalTemporary lt;
foreach (Argument a in args) {
a.Emit (ec);
- if (dup_args) {
+ if (!dup_args)
+ continue;
+
+ if (a.Expr is Constant) {
+ //
+ // No need to create a temporary variable for constants
+ //
+ temps[i] = a.Expr;
+ } else {
ec.Emit (OpCodes.Dup);
- (temps [i++] = new LocalTemporary (a.Type)).Store (ec);
+ temps[i] = lt = new LocalTemporary (a.Type);
+ lt.Store (ec);
}
- }
-
- if (dup_args) {
- if (this_arg != null)
- this_arg.Emit (ec);
- for (i = 0; i < temps.Length; i++) {
- temps[i].Emit (ec);
- temps[i].Release (ec);
- }
+ ++i;
}
+
+ return temps;
}
public List<Argument>.Enumerator GetEnumerator ()
}
}
- if (!omit_args && Arguments != null)
- Arguments.Emit (ec, dup_args, this_arg);
+ if (!omit_args && Arguments != null) {
+ var dup_arg_exprs = Arguments.Emit (ec, dup_args);
+ if (dup_args) {
+ this_arg.Emit (ec);
+ LocalTemporary lt;
+ foreach (var dup in dup_arg_exprs) {
+ dup.Emit (ec);
+ lt = dup as LocalTemporary;
+ if (lt != null)
+ lt.Release (ec);
+ }
+ }
+ }
if (call_op == OpCodes.Callvirt && (iexpr_type.IsGenericParameter || iexpr_type.IsStruct)) {
ec.Emit (OpCodes.Constrained, iexpr_type);
//
ElementAccess ea;
- LocalTemporary temp, prepared_address;
-
+ LocalTemporary temp, expr_copy;
+ Expression[] prepared_arguments;
bool prepared;
public ArrayAccess (ElementAccess ea_data, Location l)
void LoadArrayAndArguments (EmitContext ec)
{
ea.Expr.Emit (ec);
-
- for (int i = 0; i < ea.Arguments.Count; ++i) {
- ea.Arguments [i].Emit (ec);
- }
+ ea.Arguments.Emit (ec);
}
public void Emit (EmitContext ec, bool leave_copy)
var ac = ea.Expr.Type as ArrayContainer;
if (prepared) {
- if (prepared_address != null)
- prepared_address.Emit (ec);
-
ec.EmitLoadFromPtr (type);
} else {
- LoadArrayAndArguments (ec);
+ if (prepared_arguments == null) {
+ LoadArrayAndArguments (ec);
+ } else {
+ expr_copy.Emit (ec);
+ LocalTemporary lt;
+ foreach (var expr in prepared_arguments) {
+ expr.Emit (ec);
+ lt = expr as LocalTemporary;
+ if (lt != null)
+ lt.Release (ec);
+ }
+ }
+
ec.EmitArrayLoad (ac);
}
{
var ac = (ArrayContainer) ea.Expr.Type;
TypeSpec t = source.Type;
- prepared = prepare_for_load;
- LoadArrayAndArguments (ec);
-
- if (prepared) {
+ //
+ // When we are dealing with a struct, get the address of it to avoid value copy
+ // Same cannot be done for reference type because array covariance and the
+ // check in ldelema requires to specify the type of array element stored at the index
+ //
+ if (t.IsStruct && (prepare_for_load || !TypeManager.IsPrimitiveType (t))) {
+ LoadArrayAndArguments (ec);
ec.EmitArrayAddress (ac);
- if (source is DynamicExpressionStatement) {
- // Store prepared address in a variable to keep stack
- // consistent for compound dynamic operation which is
- // emitted as a method call
- prepared_address = new LocalTemporary (ReferenceContainer.MakeType (t));
- prepared_address.Store (ec);
- prepared_address.Emit (ec);
- } else {
+
+ if (prepare_for_load) {
ec.Emit (OpCodes.Dup);
}
- } else {
- //
- // If we are dealing with a struct, get the
- // address of it, so we can store it.
- //
- // The stobj opcode used by value types will need
- // an address on the stack, not really an array/array
- // pair
- //
- if (ac.Rank == 1 && TypeManager.IsStruct (t) &&
- (!TypeManager.IsBuiltinOrEnum (t) ||
- t == TypeManager.decimal_type)) {
- ec.Emit (OpCodes.Ldelema, t);
- }
+ prepared = true;
+ } else if (prepare_for_load) {
+ ea.Expr.Emit (ec);
+ ec.Emit (OpCodes.Dup);
+
+ expr_copy = new LocalTemporary (ea.Expr.Type);
+ expr_copy.Store (ec);
+ prepared_arguments = ea.Arguments.Emit (ec, true);
+ } else {
+ LoadArrayAndArguments (ec);
}
source.Emit (ec);
+
+ if (expr_copy != null) {
+ expr_copy.Release (ec);
+ }
+
if (leave_copy) {
ec.Emit (OpCodes.Dup);
temp = new LocalTemporary (this.type);
label[idx++, idx - 1] += s + s + s + s;
}
+ static bool Test_Object ()
+ {
+ int a = 0;
+ object[] o_a = new string[] { "A" };
+ o_a [a++] += "Z";
+ if ((string) o_a [0] != "AZ")
+ return false;
+
+ a = 0;
+ object[,] o_a2 = new string[,] { { "X" } };
+ o_a2[a++, 0] += "Z";
+ if ((string) o_a2 [0, 0] != "XZ")
+ return false;
+
+ return true;
+ }
+
+ static bool Test_Decimal ()
+ {
+ decimal[,] da = new decimal[,] { { 5, 6 } };
+ da[0,0] = 6.7m;
+ da[0,0] += 1.2m;
+
+ if (da [0,0] != 7.9m)
+ return false;
+
+ return true;
+ }
+
public static int Main ()
{
String str = "test";
if (sa2 [0,0] != "aaaa")
return 7;
+ if (!Test_Object ())
+ return 8;
+
+ if (!Test_Decimal ())
+ return 9;
+
return 0;
}
}
<size>74</size>
</method>
<method name="Int32 Main()">
- <size>844</size>
+ <size>842</size>
</method>
<method name="Void .ctor()">
<size>18</size>
</method>
</type>
</test>
+ <test name="dtest-cls-01.cs">
+ <type name="A">
+ <method name="Void Main()">
+ <size>1</size>
+ </method>
+ <method name="Void CLSCompliantMethod(System.Object[])">
+ <size>1</size>
+ </method>
+ <method name="Void CLSCompliantMethod(IEnumerable`1)">
+ <size>1</size>
+ </method>
+ <method name="Void .ctor()">
+ <size>7</size>
+ </method>
+ </type>
+ </test>
<test name="dtest-collectioninit-01.cs">
<type name="Test">
<method name="Int32 Main()">
<size>7</size>
</method>
<method name="Void A(System.Collections.Specialized.NameValueCollection, MyClass, System.Object)">
- <size>65</size>
+ <size>69</size>
</method>
<method name="Int32 Main()">
<size>2</size>
<size>1</size>
</method>
<method name="Boolean Test()">
- <size>110</size>
+ <size>108</size>
</method>
</type>
<type name="Driver">
<size>18</size>
</method>
<method name="Int32 i_pre_increment(X)">
- <size>27</size>
+ <size>26</size>
</method>
<method name="Int32 i_post_increment(X)">
- <size>27</size>
+ <size>26</size>
</method>
<method name="Z overload_increment(Z)">
<size>10</size>
</method>
</type>
</test>
+ <test name="test-539.cs">
+ <type name="Test">
+ <method name="Int32 Main()">
+ <size>84</size>
+ </method>
+ <method name="Void .ctor()">
+ <size>7</size>
+ </method>
+ </type>
+ <type name="<PrivateImplementationDetails>">
+ <method name="Void .ctor()">
+ <size>7</size>
+ </method>
+ </type>
+ </test>
<test name="test-54.cs">
<type name="X">
<method name="Void .ctor()">
<size>43</size>
</method>
<method name="Void BuildNode(System.String[] ByRef)">
- <size>56</size>
+ <size>58</size>
</method>
<method name="Void BuildNode_B(System.Object ByRef)">
<size>18</size>
</method>
<method name="System.String BuildNode_C(System.String ByRef)">
- <size>76</size>
+ <size>80</size>
</method>
<method name="System.String BuildNode_D()">
- <size>156</size>
+ <size>160</size>
</method>
<method name="Void BuildNode_E(System.String[,] ByRef)">
- <size>68</size>
+ <size>83</size>
</method>
<method name="Int32 Main()">
- <size>265</size>
+ <size>290</size>
+ </method>
+ <method name="Boolean Test_Object()">
+ <size>160</size>
+ </method>
+ <method name="Boolean Test_Decimal()">
+ <size>128</size>
</method>
</type>
</test>
<size>40</size>
</method>
<method name="Void TestMethod()">
- <size>71</size>
+ <size>73</size>
</method>
</type>
<type name="M">
<size>8</size>
</method>
<method name="Int32 Do(System.String, System.String, System.String)">
- <size>334</size>
+ <size>332</size>
</method>
</type>
</test>
<size>8</size>
</method>
<method name="Int32 Main()">
- <size>77</size>
+ <size>69</size>
</method>
</type>
</test>
</type>
<type name="Tester">
<method name="Int32 Main()">
- <size>80</size>
+ <size>74</size>
</method>
<method name="Void .ctor()">
<size>7</size>
<size>9</size>
</method>
<method name="Int32 Main()">
- <size>53</size>
+ <size>52</size>
</method>
<method name="Void .ctor()">
<size>7</size>
<size>7</size>
</method>
<method name="Void A(System.Collections.Specialized.NameValueCollection, MyClass, System.Object)">
- <size>65</size>
+ <size>69</size>
</method>
<method name="Int32 Main()">
<size>2</size>
<size>1</size>
</method>
<method name="Boolean Test()">
- <size>110</size>
+ <size>108</size>
</method>
</type>
<type name="Driver">
<size>18</size>
</method>
<method name="Int32 i_pre_increment(X)">
- <size>27</size>
+ <size>26</size>
</method>
<method name="Int32 i_post_increment(X)">
- <size>27</size>
+ <size>26</size>
</method>
<method name="Z overload_increment(Z)">
<size>10</size>
</method>
</type>
</test>
+ <test name="test-539.cs">
+ <type name="Test">
+ <method name="Int32 Main()">
+ <size>84</size>
+ </method>
+ <method name="Void .ctor()">
+ <size>7</size>
+ </method>
+ </type>
+ <type name="<PrivateImplementationDetails>">
+ <method name="Void .ctor()">
+ <size>7</size>
+ </method>
+ </type>
+ </test>
<test name="test-54.cs">
<type name="X">
<method name="Void .ctor()">
<size>43</size>
</method>
<method name="Void BuildNode(System.String[] ByRef)">
- <size>56</size>
+ <size>58</size>
</method>
<method name="Void BuildNode_B(System.Object ByRef)">
<size>18</size>
</method>
<method name="System.String BuildNode_C(System.String ByRef)">
- <size>76</size>
+ <size>80</size>
</method>
<method name="System.String BuildNode_D()">
- <size>156</size>
+ <size>160</size>
</method>
<method name="Void BuildNode_E(System.String[,] ByRef)">
- <size>68</size>
+ <size>83</size>
</method>
<method name="Int32 Main()">
- <size>265</size>
+ <size>290</size>
+ </method>
+ <method name="Boolean Test_Object()">
+ <size>160</size>
+ </method>
+ <method name="Boolean Test_Decimal()">
+ <size>128</size>
</method>
</type>
</test>
<size>40</size>
</method>
<method name="Void TestMethod()">
- <size>71</size>
+ <size>73</size>
</method>
</type>
<type name="M">
<size>8</size>
</method>
<method name="Int32 Do(System.String, System.String, System.String)">
- <size>334</size>
+ <size>332</size>
</method>
</type>
</test>
<size>8</size>
</method>
<method name="Int32 Main()">
- <size>77</size>
+ <size>69</size>
</method>
</type>
</test>
</type>
<type name="Tester">
<method name="Int32 Main()">
- <size>80</size>
+ <size>74</size>
</method>
<method name="Void .ctor()">
<size>7</size>
<size>9</size>
</method>
<method name="Int32 Main()">
- <size>53</size>
+ <size>52</size>
</method>
<method name="Void .ctor()">
<size>7</size>