//
// statement.cs: Statement representation for the IL tree.
//
-// Author:
+// Authors:
// Miguel de Icaza (miguel@ximian.com)
// Martin Baulig (martin@ximian.com)
-// Marek Safar (marek.safar@seznam.cz)
+// Marek Safar (marek.safar@gmail.com)
//
// Copyright 2001, 2002, 2003 Ximian, Inc.
// Copyright 2003, 2004 Novell, Inc.
HasCapturedThis = 1 << 7,
IsExpressionTree = 1 << 8,
CompilerGenerated = 1 << 9,
- IsAsync = 1 << 10
+ IsAsync = 1 << 10,
+ Resolved = 1 << 11
}
public Block Parent;
public override bool Resolve (BlockContext ec)
{
+ if ((flags & Flags.Resolved) != 0)
+ return true;
+
Block prev_block = ec.CurrentBlock;
bool ok = true;
if (this == ParametersBlock.TopBlock && !ParametersBlock.TopBlock.IsThisAssigned (ec) && !flow_unreachable)
ok = false;
+ flags |= Flags.Resolved;
return ok;
}
}
}
+ sealed class LabelMarker : Statement
+ {
+ readonly Switch s;
+ readonly List<SwitchLabel> labels;
+
+ public LabelMarker (Switch s, List<SwitchLabel> labels)
+ {
+ this.s = s;
+ this.labels = labels;
+ }
+
+ protected override void CloneTo (CloneContext clonectx, Statement target)
+ {
+ }
+
+ protected override void DoEmit (EmitContext ec)
+ {
+ foreach (var l in labels) {
+ if (l.IsDefault)
+ ec.MarkLabel (s.DefaultLabel);
+ else
+ ec.MarkLabel (l.GetILLabel (ec));
+ }
+ }
+ }
+
public List<SwitchSection> Sections;
public Expression Expr;
SwitchSection default_section;
SwitchLabel null_section;
+ Statement simple_stmt;
+ VariableReference value;
ExpressionStatement string_dictionary;
FieldExpr switch_cache_field;
static int unique_counter;
if (constant_section == null)
constant_section = default_section;
+ } else {
+ //
+ // Store switch expression for comparission purposes
+ //
+ value = new_expr as VariableReference;
+ if (value == null)
+ value = TemporaryVariableReference.Create (SwitchType, ec.CurrentBlock, loc);
}
bool first = true;
}
if (default_section == null)
- ec.CurrentBranching.CreateSibling (
- null, FlowBranching.SiblingType.SwitchSection);
+ ec.CurrentBranching.CreateSibling (null, FlowBranching.SiblingType.SwitchSection);
ec.EndFlowBranching ();
ec.Switch = old_switch;
if (!ok)
return false;
- if (SwitchType.BuiltinType == BuiltinTypeSpec.Type.String && !is_constant) {
- // TODO: Optimize single case, and single+default case
- ResolveStringSwitchMap (ec);
+ if (!is_constant) {
+ if (SwitchType.BuiltinType == BuiltinTypeSpec.Type.String) {
+ if (string_labels.Count < 7)
+ ResolveSimpleSwitch (ec);
+ else
+ ResolveStringSwitchMap (ec);
+ } else if (labels.Count < 3 && !IsNullable) {
+ ResolveSimpleSwitch (ec);
+ }
}
return true;
return sl;
}
+ //
+ // Prepares switch using simple if/else comparison for small label count (4 + optional default)
+ //
+ void ResolveSimpleSwitch (BlockContext bc)
+ {
+ simple_stmt = default_section != null ? default_section.Block : null;
+
+ for (int i = Sections.Count - 1; i >= 0; --i) {
+ var s = Sections[i];
+
+ if (s == default_section) {
+ s.Block.AddScopeStatement (new LabelMarker (this, s.Labels));
+ continue;
+ }
+
+ s.Block.AddScopeStatement (new LabelMarker (this, s.Labels));
+
+ Expression cond = null;
+ for (int ci = 0; ci < s.Labels.Count; ++ci) {
+ var e = new Binary (Binary.Operator.Equality, value, s.Labels[ci].Converted, loc);
+
+ if (ci > 0) {
+ cond = new Binary (Binary.Operator.LogicalOr, cond, e, loc);
+ } else {
+ cond = e;
+ }
+ }
+
+ simple_stmt = new If (cond, s.Block, simple_stmt, loc);
+ }
+
+ // It's null for empty switch
+ if (simple_stmt != null)
+ simple_stmt.Resolve (bc);
+ }
+
+ //
+ // Converts string switch into string hashtable
+ //
void ResolveStringSwitchMap (ResolveContext ec)
{
FullNamedExpression string_dictionary_type;
string_dictionary = new SimpleAssign (switch_cache_field, initializer.Resolve (ec));
}
- void DoEmitStringSwitch (LocalTemporary value, EmitContext ec)
+ void DoEmitStringSwitch (EmitContext ec)
{
Label l_initialized = ec.DefineLabel ();
EmitTableSwitch (ec, string_switch_variable);
string_switch_variable.Release (ec);
}
-
+
protected override void DoEmit (EmitContext ec)
{
//
default_target = ec.DefineLabel ();
null_target = ec.DefineLabel ();
- // Store variable for comparission purposes
- // TODO: Don't duplicate non-captured VariableReference
- LocalTemporary value;
if (IsNullable) {
- value = new LocalTemporary (SwitchType);
unwrap.EmitCheck (ec);
ec.Emit (OpCodes.Brfalse, null_target);
- new_expr.Emit (ec);
- value.Store (ec);
- } else if (!is_constant) {
- value = new LocalTemporary (SwitchType);
- new_expr.Emit (ec);
- value.Store (ec);
- } else
- value = null;
+ value.EmitAssign (ec, new_expr, false, false);
+ } else if (new_expr != value && !is_constant) {
+ value.EmitAssign (ec, new_expr, false, false);
+ }
//
// Setup the codegen context
if (constant_section != null)
constant_section.Block.Emit (ec);
} else if (string_dictionary != null) {
- DoEmitStringSwitch (value, ec);
+ DoEmitStringSwitch (ec);
+ } else if (simple_stmt != null) {
+ simple_stmt.Emit (ec);
} else {
EmitTableSwitch (ec, value);
}
- if (value != null)
- value.Release (ec);
-
// Restore context state.
ec.MarkLabel (ec.LoopEnd);
<size>7</size>
</method>
<method name="Int32 Main()">
- <size>101</size>
+ <size>86</size>
</method>
</type>
</test>
<size>23</size>
</method>
<method name="Int64 test11(Int32)">
- <size>44</size>
+ <size>47</size>
</method>
<method name="Void test12(Single ByRef)">
<size>20</size>
<size>23</size>
</method>
<method name="Int64 test14(Int32, Single ByRef)">
- <size>66</size>
+ <size>64</size>
</method>
<method name="Int32 test15(Int32, Single ByRef)">
<size>33</size>
<size>29</size>
</method>
<method name="Int64 test24(Int32)">
- <size>67</size>
+ <size>60</size>
</method>
<method name="Int64 test25(Int32)">
<size>34</size>
<size>31</size>
</method>
<method name="System.String test31(Int32)">
- <size>78</size>
+ <size>76</size>
</method>
<method name="Void test32()">
<size>11</size>
<size>20</size>
</method>
<method name="Void test35(Int32, Boolean)">
- <size>28</size>
+ <size>26</size>
</method>
<method name="Void test36()">
<size>41</size>
</method>
<method name="Void test37()">
- <size>42</size>
+ <size>28</size>
</method>
<method name="Int32 test38()">
<size>2</size>
<size>7</size>
</method>
<method name="Int32 Test(Int32)">
- <size>88</size>
+ <size>80</size>
</method>
<method name="Int32 Main()">
<size>7</size>
<size>7</size>
</method>
<method name="Void Main()">
- <size>701</size>
+ <size>699</size>
</method>
</type>
</test>
<size>7</size>
</method>
<method name="Void Main(System.String[])">
- <size>40</size>
+ <size>33</size>
</method>
</type>
</test>
<size>7</size>
</method>
<method name="Void Main()">
- <size>27</size>
+ <size>20</size>
</method>
</type>
</test>
<size>7</size>
</method>
<method name="Int32 ParseType(System.String)">
- <size>168</size>
+ <size>92</size>
</method>
<method name="Int32 Main()">
<size>54</size>
<size>7</size>
</method>
<method name="Int32 Main()">
- <size>40</size>
+ <size>38</size>
</method>
</type>
</test>
<size>7</size>
</method>
<method name="Void Main(System.String[])">
- <size>40</size>
+ <size>33</size>
</method>
</type>
</test>
<size>7</size>
</method>
<method name="Int32 s(Byte)">
- <size>2182</size>
+ <size>2180</size>
</method>
<method name="Int32 test(Int32)">
- <size>70</size>
+ <size>68</size>
</method>
<method name="Int32 tests(System.String)">
- <size>152</size>
+ <size>108</size>
</method>
<method name="Int32 testn(System.String)">
- <size>76</size>
+ <size>20</size>
</method>
<method name="Int32 testm(System.String)">
- <size>77</size>
+ <size>21</size>
</method>
<method name="Int32 testo(System.String)">
- <size>79</size>
+ <size>40</size>
</method>
<method name="Int32 testp(System.String)">
- <size>109</size>
+ <size>71</size>
</method>
<method name="Int32 test_def(System.String)">
- <size>119</size>
+ <size>59</size>
</method>
<method name="Int32 test_coverage(Int32)">
- <size>18</size>
+ <size>11</size>
</method>
<method name="Int32 test_goto(Int32)">
- <size>39</size>
+ <size>37</size>
</method>
<method name="Int32 test_memberaccess(System.String)">
- <size>76</size>
+ <size>20</size>
</method>
<method name="Int32 test_string_multiple_targets(System.String)">
- <size>128</size>
+ <size>82</size>
</method>
<method name="Int32 test_casts(Int32)">
- <size>17</size>
+ <size>10</size>
</method>
<method name="Int32 testSwitchEnumLong(TestEnum)">
- <size>56</size>
+ <size>54</size>
</method>
<method name="Int32 test_long_enum_switch()">
<size>66</size>
</method>
<method name="Int32 tests_default(System.String)">
- <size>107</size>
+ <size>20</size>
</method>
<method name="Int32 tests_default_2(System.String)">
- <size>124</size>
+ <size>79</size>
</method>
<method name="Void test_76590(System.String)">
- <size>107</size>
+ <size>70</size>
</method>
<method name="Void test_77964()">
- <size>37</size>
+ <size>35</size>
</method>
<method name="Boolean bug_78860()">
- <size>114</size>
+ <size>72</size>
</method>
<method name="Int32 Main()">
- <size>1037</size>
+ <size>1094</size>
+ </method>
+ <method name="Int32 tests2(System.String)">
+ <size>44</size>
</method>
</type>
</test>
<test name="test-499.cs">
<type name="A">
<method name="Int32 switch1(UInt64)">
- <size>96</size>
+ <size>94</size>
</method>
<method name="Int32 switch2(SByte)">
<size>26</size>
<size>27</size>
</method>
<method name="Int32 switch4(UInt64)">
- <size>39</size>
+ <size>37</size>
</method>
<method name="Int32 switch5(UInt64)">
<size>22</size>
<size>7</size>
</method>
<method name="Void test39(Int32 ByRef)">
- <size>36</size>
+ <size>34</size>
</method>
<method name="Void Main()">
<size>28</size>
<size>7</size>
</method>
<method name="Void Main()">
- <size>32</size>
+ <size>24</size>
</method>
</type>
</test>
<size>7</size>
</method>
<method name="Void Foo(System.String)">
- <size>49</size>
+ <size>14</size>
</method>
</type>
<type name="C2">
<size>33</size>
</method>
<method name="Void foo(Int32)">
- <size>38</size>
+ <size>31</size>
</method>
<method name="Void XXXA()">
<size>6</size>
<size>7</size>
</method>
<method name="Boolean Test(System.String)">
- <size>148</size>
+ <size>146</size>
</method>
<method name="Int32 Main()">
<size>49</size>
<size>2</size>
</method>
<method name="Void Foo(ItemSlot)">
- <size>27</size>
+ <size>20</size>
</method>
<method name="Int32 Main()">
<size>2</size>
</type>
<type name="B">
<method name="Int32 Main()">
- <size>237</size>
+ <size>184</size>
</method>
<method name="Void .ctor()">
<size>7</size>
<size>6</size>
</method>
<method name="Int32 Main()">
- <size>265</size>
+ <size>212</size>
</method>
<method name="Void .ctor()">
<size>7</size>
<size>53</size>
</method>
<method name="Void <Main>m__7(E)">
- <size>36</size>
+ <size>39</size>
</method>
<method name="Void .ctor()">
<size>7</size>
<size>35</size>
</method>
<method name="Void <Main>m__0()">
- <size>137</size>
+ <size>79</size>
</method>
<method name="Void .ctor()">
<size>7</size>
<size>112</size>
</method>
<method name="Int32 <Main>m__0(Int32)">
- <size>40</size>
+ <size>43</size>
</method>
<method name="Int32 <Main>m__1(Int32)">
- <size>35</size>
+ <size>28</size>
</method>
<method name="Int32 <Main>m__2(Int32)">
- <size>26</size>
+ <size>19</size>
</method>
<method name="Void .ctor()">
<size>7</size>
<size>3</size>
</method>
<method name="Program+D Get(Int32)">
- <size>128</size>
+ <size>126</size>
</method>
<method name="Int32 Run(Int32)">
<size>12</size>
<size>179</size>
</method>
<method name="Boolean <Main>m__0(System.Reflection.MethodInfo)">
- <size>12</size>
+ <size>37</size>
</method>
<method name="System.String <Main>m__1(System.Reflection.MethodInfo)">
<size>7</size>
</type>
<type name="Tester+<SwitchTest_1>c__async0">
<method name="Void MoveNext()">
- <size>387</size>
+ <size>409</size>
</method>
<method name="System.String <>m__4()">
<size>6</size>
<size>36</size>
</method>
</type>
- <type name="Tester+<Using_1>c__async1+<Using_1>c__AnonStorey3">
+ <type name="Tester+<SwitchTest_1>c__async0+<SwitchTest_1>c__AnonStorey3">
+ <method name="Void .ctor()">
+ <size>7</size>
+ </method>
+ </type>
+ <type name="Tester+<Using_1>c__async1+<Using_1>c__AnonStorey4">
<method name="Void .ctor()">
<size>7</size>
</method>
</type>
- <type name="Tester+<Foreach_1>c__async2+<Foreach_1>c__AnonStorey4">
+ <type name="Tester+<Foreach_1>c__async2+<Foreach_1>c__AnonStorey5">
<method name="Void .ctor()">
<size>7</size>
</method>