/// </summary>
protected abstract void DoEmit (EmitContext ec);
+ /// <summary>
+ /// Utility wrapper routine for Error, just to beautify the code
+ /// </summary>
+ public void Error (int error, string format, params object[] args)
+ {
+ Error (error, String.Format (format, args));
+ }
+
+ public void Error (int error, string s)
+ {
+ if (!Location.IsNull (loc))
+ Report.Error (error, loc, s);
+ else
+ Report.Error (error, s);
+ }
+
/// <summary>
/// Return value indicates whether all code paths emitted return.
/// </summary>
is_true_ret = ec.CurrentBranching.CurrentUsageVector.Reachability.IsUnreachable;
- ec.CurrentBranching.CreateSibling (FlowBranching.SiblingType.Conditional);
+ ec.CurrentBranching.CreateSibling ();
if ((FalseStatement != null) && !FalseStatement.Resolve (ec))
ok = false;
{
bool ok = true;
- ec.StartFlowBranching (FlowBranching.BranchingType.LoopBlock, loc);
+ ec.StartFlowBranching (FlowBranching.BranchingType.Loop, loc);
if (!EmbeddedStatement.Resolve (ec))
ok = false;
Label loop = ig.DefineLabel ();
Label old_begin = ec.LoopBegin;
Label old_end = ec.LoopEnd;
- bool old_inloop = ec.InLoop;
- int old_loop_begin_try_catch_level = ec.LoopBeginTryCatchLevel;
ec.LoopBegin = ig.DefineLabel ();
ec.LoopEnd = ig.DefineLabel ();
- ec.InLoop = true;
- ec.LoopBeginTryCatchLevel = ec.TryCatchLevel;
ig.MarkLabel (loop);
EmbeddedStatement.Emit (ec);
ig.MarkLabel (ec.LoopEnd);
- ec.LoopBeginTryCatchLevel = old_loop_begin_try_catch_level;
ec.LoopBegin = old_begin;
ec.LoopEnd = old_end;
- ec.InLoop = old_inloop;
}
}
infinite = true;
}
- ec.StartFlowBranching (FlowBranching.BranchingType.LoopBlock, loc);
+ ec.StartFlowBranching (FlowBranching.BranchingType.Loop, loc);
if (!Statement.Resolve (ec))
ok = false;
ILGenerator ig = ec.ig;
Label old_begin = ec.LoopBegin;
Label old_end = ec.LoopEnd;
- bool old_inloop = ec.InLoop;
- int old_loop_begin_try_catch_level = ec.LoopBeginTryCatchLevel;
ec.LoopBegin = ig.DefineLabel ();
ec.LoopEnd = ig.DefineLabel ();
- ec.InLoop = true;
- ec.LoopBeginTryCatchLevel = ec.TryCatchLevel;
//
// Inform whether we are infinite or not
ec.LoopBegin = old_begin;
ec.LoopEnd = old_end;
- ec.InLoop = old_inloop;
- ec.LoopBeginTryCatchLevel = old_loop_begin_try_catch_level;
}
}
} else
infinite = true;
- ec.StartFlowBranching (FlowBranching.BranchingType.LoopBlock, loc);
+ ec.StartFlowBranching (FlowBranching.BranchingType.Loop, loc);
if (!infinite)
- ec.CurrentBranching.CreateSibling (FlowBranching.SiblingType.Conditional);
+ ec.CurrentBranching.CreateSibling ();
if (!Statement.Resolve (ec))
ok = false;
ILGenerator ig = ec.ig;
Label old_begin = ec.LoopBegin;
Label old_end = ec.LoopEnd;
- bool old_inloop = ec.InLoop;
- int old_loop_begin_try_catch_level = ec.LoopBeginTryCatchLevel;
Label loop = ig.DefineLabel ();
Label test = ig.DefineLabel ();
ec.LoopBegin = ig.DefineLabel ();
ec.LoopEnd = ig.DefineLabel ();
- ec.InLoop = true;
- ec.LoopBeginTryCatchLevel = ec.TryCatchLevel;
ig.Emit (OpCodes.Br, test);
ig.MarkLabel (loop);
ec.LoopBegin = old_begin;
ec.LoopEnd = old_end;
- ec.InLoop = old_inloop;
- ec.LoopBeginTryCatchLevel = old_loop_begin_try_catch_level;
}
}
loc = l;
}
+ bool in_exc;
+
public override bool Resolve (EmitContext ec)
{
- if (Expr != null){
+ if (ec.ReturnType == null){
+ if (Expr != null){
+ Error (127, "Return with a value not allowed here");
+ return false;
+ }
+ } else {
+ if (Expr == null){
+ Error (126, "An object of type `{0}' is expected " +
+ "for the return statement",
+ TypeManager.CSharpName (ec.ReturnType));
+ return false;
+ }
+
Expr = Expr.Resolve (ec);
if (Expr == null)
return false;
+
+ if (Expr.Type != ec.ReturnType) {
+ Expr = Convert.ImplicitConversionRequired (
+ ec, Expr, ec.ReturnType, loc);
+ if (Expr == null)
+ return false;
+ }
}
if (ec.InIterator){
- Report.Error (-206, loc, "Return statement not allowed inside iterators");
+ Error (-206, "Return statement not allowed inside iterators");
return false;
}
FlowBranching.UsageVector vector = ec.CurrentBranching.CurrentUsageVector;
- if (ec.CurrentBranching.InTryBlock ())
+ if (ec.CurrentBranching.InTryOrCatch (true)) {
ec.CurrentBranching.AddFinallyVector (vector);
- else
+ in_exc = true;
+ } else if (ec.CurrentBranching.InFinally (true)) {
+ Error (157, "Control can not leave the body of the finally block");
+ return false;
+ } else
vector.CheckOutParameters (ec.CurrentBranching);
ec.CurrentBranching.CurrentUsageVector.Return ();
protected override void DoEmit (EmitContext ec)
{
- if (ec.InFinally){
- Report.Error (157, loc, "Control can not leave the body of the finally block");
- return;
- }
-
- if (ec.ReturnType == null){
- if (Expr != null){
- Report.Error (127, loc, "Return with a value not allowed here");
- return;
- }
- } else {
- if (Expr == null){
- Report.Error (126, loc, "An object of type `" +
- TypeManager.CSharpName (ec.ReturnType) + "' is " +
- "expected for the return statement");
- return;
- }
-
- if (Expr.Type != ec.ReturnType)
- Expr = Convert.ImplicitConversionRequired (
- ec, Expr, ec.ReturnType, loc);
-
- if (Expr == null)
- return;
-
+ if (Expr != null) {
Expr.Emit (ec);
- if (ec.InTry || ec.InCatch)
+ if (in_exc)
ec.ig.Emit (OpCodes.Stloc, ec.TemporaryReturn ());
}
- if (ec.InTry || ec.InCatch) {
- if (!ec.HasReturnLabel) {
- ec.ReturnLabel = ec.ig.DefineLabel ();
- ec.HasReturnLabel = true;
- }
+ if (in_exc) {
+ ec.NeedReturnLabel ();
ec.ig.Emit (OpCodes.Leave, ec.ReturnLabel);
} else {
ec.ig.Emit (OpCodes.Ret);
- ec.NeedExplicitReturn = false;
}
}
}
public override bool Resolve (EmitContext ec)
{
- label = block.LookupLabel (target);
- if (label == null){
- Report.Error (
- 159, loc,
- "No such label `" + target + "' in this scope");
+ label = ec.CurrentBranching.LookupLabel (target, loc);
+ if (label == null)
return false;
- }
// If this is a forward goto.
if (!label.IsDefined)
bool referenced;
Label label;
- ArrayList vectors;
+ FlowBranching.UsageVector vectors;
public LabeledStatement (string label_name, Location l)
{
public void AddUsageVector (FlowBranching.UsageVector vector)
{
- if (vectors == null)
- vectors = new ArrayList ();
-
- vectors.Add (vector.Clone ());
+ vector = vector.Clone ();
+ vector.Next = vectors;
+ vectors = vector;
}
public override bool Resolve (EmitContext ec)
public override bool Resolve (EmitContext ec)
{
+ bool in_catch = ec.CurrentBranching.InCatch ();
+ ec.CurrentBranching.CurrentUsageVector.Throw ();
+
if (expr != null){
expr = expr.Resolve (ec);
if (expr == null)
if ((t != TypeManager.exception_type) &&
!t.IsSubclassOf (TypeManager.exception_type) &&
!(expr is NullLiteral)) {
- Report.Error (155, loc,
- "The type caught or thrown must be derived " +
- "from System.Exception");
+ Error (155,
+ "The type caught or thrown must be derived " +
+ "from System.Exception");
return false;
}
+ } else if (!in_catch) {
+ Error (156,
+ "A throw statement with no argument is only " +
+ "allowed in a catch clause");
+ return false;
}
- ec.CurrentBranching.CurrentUsageVector.Throw ();
return true;
}
protected override void DoEmit (EmitContext ec)
{
- if (expr == null){
- if (ec.InCatch)
- ec.ig.Emit (OpCodes.Rethrow);
- else {
- Report.Error (
- 156, loc,
- "A throw statement with no argument is only " +
- "allowed in a catch clause");
- }
- return;
- }
-
- expr.Emit (ec);
+ if (expr == null)
+ ec.ig.Emit (OpCodes.Rethrow);
+ else {
+ expr.Emit (ec);
- ec.ig.Emit (OpCodes.Throw);
+ ec.ig.Emit (OpCodes.Throw);
+ }
}
}
loc = l;
}
+ bool crossing_exc;
+
public override bool Resolve (EmitContext ec)
{
+ if (!ec.CurrentBranching.InLoop () && !ec.CurrentBranching.InSwitch ()){
+ Error (139, "No enclosing loop or switch to continue to");
+ return false;
+ } else if (ec.CurrentBranching.InFinally (false)) {
+ Error (157, "Control can not leave the body of the finally block");
+ return false;
+ } else if (ec.CurrentBranching.InTryOrCatch (false))
+ ec.CurrentBranching.AddFinallyVector (
+ ec.CurrentBranching.CurrentUsageVector);
+ else if (ec.CurrentBranching.InLoop ())
+ ec.CurrentBranching.AddBreakVector (
+ ec.CurrentBranching.CurrentUsageVector);
+
+ crossing_exc = ec.CurrentBranching.BreakCrossesTryCatchBoundary ();
+
ec.CurrentBranching.CurrentUsageVector.Break ();
return true;
}
{
ILGenerator ig = ec.ig;
- if (ec.InLoop == false && ec.Switch == null){
- Report.Error (139, loc, "No enclosing loop or switch to continue to");
- return;
- }
-
- if (ec.InTry || ec.InCatch)
+ if (crossing_exc)
ig.Emit (OpCodes.Leave, ec.LoopEnd);
else {
- ec.NeedExplicitReturn = true;
+ ec.NeedReturnLabel ();
ig.Emit (OpCodes.Br, ec.LoopEnd);
}
}
loc = l;
}
+ bool crossing_exc;
+
public override bool Resolve (EmitContext ec)
{
+ if (!ec.CurrentBranching.InLoop () && !ec.CurrentBranching.InSwitch ()){
+ Error (139, "No enclosing loop to continue to");
+ return false;
+ } else if (ec.CurrentBranching.InFinally (false)) {
+ Error (157, "Control can not leave the body of the finally block");
+ return false;
+ } else if (ec.CurrentBranching.InTryOrCatch (false))
+ ec.CurrentBranching.AddFinallyVector (ec.CurrentBranching.CurrentUsageVector);
+
+ crossing_exc = ec.CurrentBranching.BreakCrossesTryCatchBoundary ();
+
ec.CurrentBranching.CurrentUsageVector.Goto ();
return true;
}
{
Label begin = ec.LoopBegin;
- if (!ec.InLoop){
- Report.Error (139, loc, "No enclosing loop to continue to");
- return;
- }
-
- //
- // UGH: Non trivial. This Br might cross a try/catch boundary
- // How can we tell?
- //
- // while () {
- // try { ... } catch { continue; }
- // }
- //
- // From:
- // try {} catch { while () { continue; }}
- //
- if (ec.TryCatchLevel > ec.LoopBeginTryCatchLevel)
+ if (crossing_exc)
ec.ig.Emit (OpCodes.Leave, begin);
- else if (ec.TryCatchLevel < ec.LoopBeginTryCatchLevel)
- throw new Exception ("Should never happen");
else
ec.ig.Emit (OpCodes.Br, begin);
}
if (VariableType == null)
VariableType = decl.ResolveType (Type, false, Location);
+ if (VariableType == TypeManager.void_type) {
+ Report.Error (1547, Location,
+ "Keyword 'void' cannot be used in this context");
+ return false;
+ }
+
if (VariableType == null)
return false;
Unchecked = 2,
BlockUsed = 4,
VariablesInitialized = 8,
- HasRet = 16
+ HasRet = 16,
+ IsDestructor = 32
}
Flags flags;
// The statements in this block
//
ArrayList statements;
+ int num_statements;
//
// An array of Blocks. We keep track of children just
this.loc = start;
this_id = id++;
statements = new ArrayList ();
+
+ if (parent != null && Implicit) {
+ if (parent.child_variable_names == null)
+ parent.child_variable_names = new Hashtable();
+ // share with parent
+ child_variable_names = parent.child_variable_names;
+ }
+
}
public Block CreateSwitchBlock (Location start)
/// otherwise.
/// </returns>
///
- public bool AddLabel (string name, LabeledStatement target)
+ public bool AddLabel (string name, LabeledStatement target, Location loc)
{
if (switch_block != null)
- return switch_block.AddLabel (name, target);
+ return switch_block.AddLabel (name, target, loc);
+
+ Block cur = this;
+ while (cur != null) {
+ if (cur.DoLookupLabel (name) != null) {
+ Report.Error (
+ 140, loc, "The label '{0}' is a duplicate",
+ name);
+ return false;
+ }
+
+ if (!Implicit)
+ break;
+
+ cur = cur.Parent;
+ }
+
+ while (cur != null) {
+ if (cur.DoLookupLabel (name) != null) {
+ Report.Error (
+ 158, loc,
+ "The label '{0}' shadows another label " +
+ "by the same name in a containing scope.",
+ name);
+ return false;
+ }
+
+ if (children != null) {
+ foreach (Block b in children) {
+ LabeledStatement s = b.DoLookupLabel (name);
+ if (s == null)
+ continue;
+
+ Report.Error (
+ 158, s.Location,
+ "The label '{0}' shadows another " +
+ "label by the same name in a " +
+ "containing scope.",
+ name);
+ return false;
+ }
+ }
+
+
+ cur = cur.Parent;
+ }
if (labels == null)
labels = new Hashtable ();
- if (labels.Contains (name))
- return false;
-
+
labels.Add (name, target);
return true;
}
public LabeledStatement LookupLabel (string name)
{
- Hashtable l = new Hashtable ();
-
- return LookupLabel (name, l);
+ LabeledStatement s = DoLookupLabel (name);
+ if (s != null)
+ return s;
+
+ if (children == null)
+ return null;
+
+ foreach (Block child in children) {
+ if (!child.Implicit)
+ continue;
+
+ s = child.LookupLabel (name);
+ if (s != null)
+ return s;
+ }
+
+ return null;
}
- //
- // Lookups a label in the current block, parents and children.
- // It skips during child recurssion on `source'
- //
- LabeledStatement LookupLabel (string name, Hashtable seen)
+ LabeledStatement DoLookupLabel (string name)
{
if (switch_block != null)
- return switch_block.LookupLabel (name, seen);
-
- if (seen [this] != null)
- return null;
+ return switch_block.LookupLabel (name);
- seen [this] = this;
-
if (labels != null)
if (labels.Contains (name))
return ((LabeledStatement) labels [name]);
- if (children != null){
- foreach (Block b in children){
- LabeledStatement s = b.LookupLabel (name, seen);
- if (s != null)
- return s;
- }
- }
-
- if (Parent != null)
- return Parent.LookupLabel (name, seen);
-
return null;
}
child_variable_names.Add (name, true);
}
- // <summary>
- // Marks all variables from block @block and all its children as being
- // used in a child block.
- // </summary>
- public void AddChildVariableNames (Block block)
- {
- if (block.Variables != null) {
- foreach (string name in block.Variables.Keys)
- AddChildVariableName (name);
- }
-
- if (block.children != null) {
- foreach (Block child in block.children)
- AddChildVariableNames (child);
- }
-
- if (block.child_variable_names != null) {
- foreach (string name in block.child_variable_names.Keys)
- AddChildVariableName (name);
- }
- }
-
// <summary>
// Checks whether a variable name has already been used in a child block.
// </summary>
return null;
}
}
-
+
vi = new LocalInfo (type, name, this, l);
variables.Add (name, vi);
+ // Mark 'name' as "used by a child block" in every surrounding block
+ Block cur = this;
+ while (cur != null && cur.Implicit)
+ cur = cur.Parent;
+ if (cur != null)
+ for (Block par = cur.Parent; par != null; par = par.Parent)
+ par.AddChildVariableName (name);
+
if ((flags & Flags.VariablesInitialized) != 0)
throw new Exception ();
return e != null;
}
- /// <summary>
- /// Use to fetch the statement associated with this label
- /// </summary>
- public Statement this [string name] {
- get {
- return (Statement) labels [name];
- }
- }
-
Parameters parameters = null;
public Parameters Parameters {
get {
}
}
+ public bool IsDestructor {
+ get {
+ return (flags & Flags.IsDestructor) != 0;
+ }
+ }
+
+ public void SetDestructor ()
+ {
+ flags |= Flags.IsDestructor;
+ }
+
VariableMap param_map, local_map;
public VariableMap ParameterMap {
ec.StartFlowBranching (this);
Report.Debug (4, "RESOLVE BLOCK", StartLocation, ec.CurrentBranching);
-
+
bool unreachable = false, warning_shown = false;
int statement_count = statements.Count;
Statement s = (Statement) statements [ix];
if (unreachable && !(s is LabeledStatement)) {
+ if (s == EmptyStatement.Value)
+ s.loc = EndLocation;
+
if (!s.ResolveUnreachable (ec, !warning_shown))
ok = false;
if (s != EmptyStatement.Value)
warning_shown = true;
+ else
+ s.loc = Location.Null;
statements [ix] = EmptyStatement.Value;
continue;
continue;
}
+ num_statements = ix + 1;
+
if (s is LabeledStatement)
unreachable = false;
else
unreachable = ec.CurrentBranching.CurrentUsageVector.Reachability.IsUnreachable;
}
- Report.Debug (4, "RESOLVE BLOCK DONE", StartLocation, ec.CurrentBranching);
+ Report.Debug (4, "RESOLVE BLOCK DONE", StartLocation,
+ ec.CurrentBranching, statement_count, num_statements);
FlowBranching.UsageVector vector = ec.DoEndFlowBranching ();
protected override void DoEmit (EmitContext ec)
{
- int statement_count = statements.Count;
- for (int ix = 0; ix < statement_count; ix++){
+ for (int ix = 0; ix < num_statements; ix++){
Statement s = (Statement) statements [ix];
+
+ // Check whether we are the last statement in a
+ // top-level block.
+
+ if ((Parent == null) && (ix+1 == num_statements))
+ ec.IsLastStatement = true;
+ else
+ ec.IsLastStatement = false;
+
s.Emit (ec);
}
}
}
if (error)
return false;
-
+
return true;
}
public long nFirst;
public long nLast;
public ArrayList rgKeys = null;
+ // how many items are in the bucket
+ public int Size = 1;
public int Length
{
get { return (int) (nLast - nFirst + 1); }
for (int ikb = 1; ikb < rgKeyBlocks.Count; ikb++)
{
KeyBlock kb = (KeyBlock) rgKeyBlocks [ikb];
- if ((kbCurr.Length + kb.Length) * 2 >= KeyBlock.TotalLength (kbCurr, kb))
+ if ((kbCurr.Size + kb.Size) * 2 >= KeyBlock.TotalLength (kbCurr, kb))
{
// merge blocks
kbCurr.nLast = kb.nLast;
+ kbCurr.Size += kb.Size;
}
else
{
bool first_test = true;
bool pending_goto_end = false;
bool null_found;
+ bool default_at_end = false;
ig.Emit (OpCodes.Ldloc, val);
ig.Emit (OpCodes.Br, end_of_switch);
int label_count = ss.Labels.Count;
+ bool mark_default = false;
null_found = false;
for (int label = 0; label < label_count; label++){
SwitchLabel sl = (SwitchLabel) ss.Labels [label];
// If we are the default target
//
if (sl.Label == null){
- ig.MarkLabel (default_target);
+ if (label+1 == label_count)
+ default_at_end = true;
+ mark_default = true;
default_found = true;
} else {
object lit = sl.Converted;
foreach (SwitchLabel sl in ss.Labels)
ig.MarkLabel (sl.ILLabelCode);
+ if (mark_default)
+ ig.MarkLabel (default_target);
ss.Block.Emit (ec);
pending_goto_end = !ss.Block.HasRet;
first_test = false;
}
- if (!default_found){
- ig.MarkLabel (default_target);
- }
ig.MarkLabel (next_test);
+ if (default_found){
+ if (!default_at_end)
+ ig.Emit (OpCodes.Br, default_target);
+ } else
+ ig.MarkLabel (default_target);
ig.MarkLabel (end_of_switch);
}
ec.Switch = this;
ec.Switch.SwitchType = SwitchType;
+ Report.Debug (1, "START OF SWITCH BLOCK", loc, ec.CurrentBranching);
ec.StartFlowBranching (FlowBranching.BranchingType.Switch, loc);
bool first = true;
foreach (SwitchSection ss in Sections){
if (!first)
- ec.CurrentBranching.CreateSibling (FlowBranching.SiblingType.SwitchSection);
+ ec.CurrentBranching.CreateSibling (
+ null, FlowBranching.SiblingType.SwitchSection);
else
first = false;
if (!got_default)
- ec.CurrentBranching.CreateSibling (FlowBranching.SiblingType.SwitchSection);
+ ec.CurrentBranching.CreateSibling (
+ null, FlowBranching.SiblingType.SwitchSection);
- ec.EndFlowBranching ();
+ FlowBranching.Reachability reachability = ec.EndFlowBranching ();
ec.Switch = old_switch;
+ Report.Debug (1, "END OF SWITCH BLOCK", loc, ec.CurrentBranching,
+ reachability);
+
return true;
}
public override bool Resolve (EmitContext ec)
{
expr = expr.Resolve (ec);
- return Statement.Resolve (ec) && expr != null;
+ if (expr == null)
+ return false;
+
+ if (expr.Type.IsValueType){
+ Error (185, "lock statement requires the expression to be " +
+ " a reference type (type is: `{0}'",
+ TypeManager.CSharpName (expr.Type));
+ return false;
+ }
+
+ ec.StartFlowBranching (FlowBranching.BranchingType.Exception, loc);
+ bool ok = Statement.Resolve (ec);
+ ec.EndFlowBranching ();
+
+ return ok;
}
protected override void DoEmit (EmitContext ec)
{
Type type = expr.Type;
- if (type.IsValueType){
- Report.Error (185, loc, "lock statement requires the expression to be " +
- " a reference type (type is: `" +
- TypeManager.CSharpName (type) + "'");
- return;
- }
-
ILGenerator ig = ec.ig;
LocalBuilder temp = ig.DeclareLocal (type);
// try
ig.BeginExceptionBlock ();
- bool old_in_try = ec.InTry;
- ec.InTry = true;
Label finish = ig.DefineLabel ();
Statement.Emit (ec);
- ec.InTry = old_in_try;
// ig.Emit (OpCodes.Leave, finish);
ig.MarkLabel (finish);
Report.Debug (1, "START OF TRY BLOCK", Block.StartLocation);
- bool old_in_try = ec.InTry;
- ec.InTry = true;
-
if (!Block.Resolve (ec))
ok = false;
- ec.InTry = old_in_try;
-
FlowBranching.UsageVector vector = ec.CurrentBranching.CurrentUsageVector;
Report.Debug (1, "START OF CATCH BLOCKS", vector);
foreach (Catch c in Specific){
- ec.CurrentBranching.CreateSibling (FlowBranching.SiblingType.Catch);
+ ec.CurrentBranching.CreateSibling (
+ c.Block, FlowBranching.SiblingType.Catch);
+
Report.Debug (1, "STARTED SIBLING FOR CATCH", ec.CurrentBranching);
if (c.Name != null) {
vi.VariableInfo = null;
}
- bool old_in_catch = ec.InCatch;
- ec.InCatch = true;
-
if (!c.Resolve (ec))
ok = false;
-
- ec.InCatch = old_in_catch;
}
Report.Debug (1, "END OF CATCH BLOCKS", ec.CurrentBranching);
if (General != null){
- ec.CurrentBranching.CreateSibling (FlowBranching.SiblingType.Catch);
- Report.Debug (1, "STARTED SIBLING FOR GENERAL", ec.CurrentBranching);
+ ec.CurrentBranching.CreateSibling (
+ General.Block, FlowBranching.SiblingType.Catch);
- bool old_in_catch = ec.InCatch;
- ec.InCatch = true;
+ Report.Debug (1, "STARTED SIBLING FOR GENERAL", ec.CurrentBranching);
if (!General.Resolve (ec))
ok = false;
-
- ec.InCatch = old_in_catch;
}
Report.Debug (1, "END OF GENERAL CATCH BLOCKS", ec.CurrentBranching);
if (Fini != null) {
if (ok)
- ec.CurrentBranching.CreateSibling (FlowBranching.SiblingType.Finally);
- Report.Debug (1, "STARTED SIBLING FOR FINALLY", ec.CurrentBranching, vector);
+ ec.CurrentBranching.CreateSibling (
+ Fini, FlowBranching.SiblingType.Finally);
- bool old_in_finally = ec.InFinally;
- ec.InFinally = true;
+ Report.Debug (1, "STARTED SIBLING FOR FINALLY", ec.CurrentBranching, vector);
if (!Fini.Resolve (ec))
ok = false;
-
- ec.InFinally = old_in_finally;
}
FlowBranching.Reachability reachability = ec.EndFlowBranching ();
// to the end of the finally block. This is a problem if `returns'
// is true since we may jump to a point after the end of the method.
// As a workaround, emit an explicit ret here.
- ec.NeedExplicitReturn = true;
+ ec.NeedReturnLabel ();
}
return ok;
ILGenerator ig = ec.ig;
Label finish = ig.DefineLabel ();;
- ec.TryCatchLevel++;
ig.BeginExceptionBlock ();
- bool old_in_try = ec.InTry;
- ec.InTry = true;
Block.Emit (ec);
- ec.InTry = old_in_try;
//
// System.Reflection.Emit provides this automatically:
// ig.Emit (OpCodes.Leave, finish);
- bool old_in_catch = ec.InCatch;
- ec.InCatch = true;
-
foreach (Catch c in Specific){
LocalInfo vi;
ig.Emit (OpCodes.Pop);
General.Block.Emit (ec);
}
- ec.InCatch = old_in_catch;
ig.MarkLabel (finish);
if (Fini != null){
ig.BeginFinallyBlock ();
- bool old_in_finally = ec.InFinally;
- ec.InFinally = true;
Fini.Emit (ec);
- ec.InFinally = old_in_finally;
}
ig.EndExceptionBlock ();
- ec.TryCatchLevel--;
}
}
ILGenerator ig = ec.ig;
int i = 0;
- bool old_in_try = ec.InTry;
- ec.InTry = true;
for (i = 0; i < assign.Length; i++) {
assign [i].EmitStatement (ec);
ig.BeginExceptionBlock ();
}
Statement.Emit (ec);
- ec.InTry = old_in_try;
- bool old_in_finally = ec.InFinally;
- ec.InFinally = true;
var_list.Reverse ();
foreach (DictionaryEntry e in var_list){
LocalVariableReference var = (LocalVariableReference) e.Key;
converted_vars [i].Emit (ec);
ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void);
} else {
- Expression ml = Expression.MemberLookup(ec, typeof(IDisposable), var.Type, "Dispose", Mono.CSharp.Location.Null);
+ Expression ml = Expression.MemberLookup(ec, TypeManager.idisposable_type, var.Type, "Dispose", Mono.CSharp.Location.Null);
if (!(ml is MethodGroupExpr)) {
var.Emit (ec);
ig.MarkLabel (skip);
ig.EndExceptionBlock ();
}
- ec.InFinally = old_in_finally;
return false;
}
expr.Emit (ec);
ig.Emit (OpCodes.Stloc, local_copy);
- bool old_in_try = ec.InTry;
- ec.InTry = true;
ig.BeginExceptionBlock ();
Statement.Emit (ec);
- ec.InTry = old_in_try;
Label skip = ig.DefineLabel ();
- bool old_in_finally = ec.InFinally;
ig.BeginFinallyBlock ();
ig.Emit (OpCodes.Ldloc, local_copy);
ig.Emit (OpCodes.Brfalse, skip);
ig.Emit (OpCodes.Ldloc, local_copy);
ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void);
ig.MarkLabel (skip);
- ec.InFinally = old_in_finally;
ig.EndExceptionBlock ();
return false;
return false;
}
- ec.StartFlowBranching (FlowBranching.BranchingType.Block, loc);
+ ec.StartFlowBranching (FlowBranching.BranchingType.Exception, loc);
bool ok = Statement.Resolve (ec);
// to the end of the finally block. This is a problem if `returns'
// is true since we may jump to a point after the end of the method.
// As a workaround, emit an explicit ret here.
- ec.NeedExplicitReturn = true;
+ ec.NeedReturnLabel ();
}
return true;
if (hm == null){
error1579 (expr.Type);
return false;
- }
+ }
array_type = expr.Type;
element_type = hm.element_type;
empty = new EmptyExpression (hm.element_type);
}
- ec.StartFlowBranching (FlowBranching.BranchingType.LoopBlock, loc);
- ec.CurrentBranching.CreateSibling (FlowBranching.SiblingType.Conditional);
+ bool ok = true;
+
+ ec.StartFlowBranching (FlowBranching.BranchingType.Loop, loc);
+ ec.CurrentBranching.CreateSibling ();
//
//
//
conv = Convert.ExplicitConversion (ec, empty, var_type, loc);
if (conv == null)
- return false;
+ ok = false;
variable = variable.ResolveLValue (ec, empty);
if (variable == null)
- return false;
+ ok = false;
+
+ bool disposable = (hm != null) && hm.is_disposable;
+ if (disposable)
+ ec.StartFlowBranching (FlowBranching.BranchingType.Exception, loc);
if (!statement.Resolve (ec))
- return false;
+ ok = false;
+
+ if (disposable)
+ ec.EndFlowBranching ();
ec.EndFlowBranching ();
- return true;
+ return ok;
}
//
// Ok, we can access it, now make sure that we can do something
// with this `GetEnumerator'
//
-
+
+ Type return_type = mi.ReturnType;
if (mi.ReturnType == TypeManager.ienumerator_type ||
- TypeManager.ienumerator_type.IsAssignableFrom (mi.ReturnType) ||
- (!RootContext.StdLib && TypeManager.ImplementsInterface (mi.ReturnType, TypeManager.ienumerator_type))) {
- if (declaring != TypeManager.string_type) {
+ TypeManager.ienumerator_type.IsAssignableFrom (return_type) ||
+ (!RootContext.StdLib && TypeManager.ImplementsInterface (return_type, TypeManager.ienumerator_type))) {
+
+ //
+ // If it is not an interface, lets try to find the methods ourselves.
+ // For example, if we have:
+ // public class Foo : IEnumerator { public bool MoveNext () {} public int Current { get {}}}
+ // We can avoid the iface call. This is a runtime perf boost.
+ // even bigger if we have a ValueType, because we avoid the cost
+ // of boxing.
+ //
+ // We have to make sure that both methods exist for us to take
+ // this path. If one of the methods does not exist, we will just
+ // use the interface. Sadly, this complex if statement is the only
+ // way I could do this without a goto
+ //
+
+ if (return_type.IsInterface ||
+ (hm.move_next = FetchMethodMoveNext (return_type)) == null ||
+ (hm.get_current = FetchMethodGetCurrent (return_type)) == null) {
+
hm.move_next = TypeManager.bool_movenext_void;
hm.get_current = TypeManager.object_getcurrent_void;
- return true;
+ return true;
}
- }
- //
- // Ok, so they dont return an IEnumerable, we will have to
- // find if they support the GetEnumerator pattern.
- //
- Type return_type = mi.ReturnType;
-
- hm.move_next = FetchMethodMoveNext (return_type);
- if (hm.move_next == null)
- return false;
- hm.get_current = FetchMethodGetCurrent (return_type);
- if (hm.get_current == null)
- return false;
+ } else {
+ //
+ // Ok, so they dont return an IEnumerable, we will have to
+ // find if they support the GetEnumerator pattern.
+ //
+
+ hm.move_next = FetchMethodMoveNext (return_type);
+ if (hm.move_next == null)
+ return false;
+
+ hm.get_current = FetchMethodGetCurrent (return_type);
+ if (hm.get_current == null)
+ return false;
+ }
+
hm.element_type = hm.get_current.ReturnType;
hm.enumerator_type = return_type;
hm.is_disposable = !hm.enumerator_type.IsSealed ||
bool EmitCollectionForeach (EmitContext ec)
{
ILGenerator ig = ec.ig;
- VariableStorage enumerator, disposable;
+ VariableStorage enumerator;
enumerator = new VariableStorage (ec, hm.enumerator_type);
- if (hm.is_disposable)
- disposable = new VariableStorage (ec, TypeManager.idisposable_type);
- else
- disposable = null;
-
enumerator.EmitThis ();
//
// Instantiate the enumerator
if (expr is IMemoryLocation){
IMemoryLocation ml = (IMemoryLocation) expr;
- ml.AddressOf (ec, AddressOp.Load);
+ Expression ml1 = Expression.MemberLookup(ec, TypeManager.ienumerator_type, expr.Type, "GetEnumerator", Mono.CSharp.Location.Null);
+
+ if (!(ml1 is MethodGroupExpr)) {
+ expr.Emit(ec);
+ ec.ig.Emit(OpCodes.Box, expr.Type);
+ } else {
+ ml.AddressOf (ec, AddressOp.Load);
+ }
} else
throw new Exception ("Expr " + expr + " of type " + expr.Type +
" does not implement IMemoryLocation");
- ig.Emit (OpCodes.Call, hm.get_enumerator);
+ ig.Emit (OpCodes.Callvirt, hm.get_enumerator);
} else {
expr.Emit (ec);
ig.Emit (OpCodes.Callvirt, hm.get_enumerator);
// Protect the code in a try/finalize block, so that
// if the beast implement IDisposable, we get rid of it
//
- bool old_in_try = ec.InTry;
-
- if (hm.is_disposable) {
+ if (hm.is_disposable)
ig.BeginExceptionBlock ();
- ec.InTry = true;
- }
Label end_try = ig.DefineLabel ();
ig.MarkLabel (ec.LoopBegin);
- enumerator.EmitLoad ();
- ig.Emit (OpCodes.Callvirt, hm.move_next);
+
+ enumerator.EmitCall (hm.move_next);
+
ig.Emit (OpCodes.Brfalse, end_try);
if (ec.InIterator)
ec.EmitThis ();
- enumerator.EmitLoad ();
- ig.Emit (OpCodes.Callvirt, hm.get_current);
+ enumerator.EmitCall (hm.get_current);
if (ec.InIterator){
conv.Emit (ec);
statement.Emit (ec);
ig.Emit (OpCodes.Br, ec.LoopBegin);
ig.MarkLabel (end_try);
- ec.InTry = old_in_try;
// The runtime provides this for us.
// ig.Emit (OpCodes.Leave, end);
// Now the finally block
//
if (hm.is_disposable) {
- Label end_finally = ig.DefineLabel ();
- bool old_in_finally = ec.InFinally;
- ec.InFinally = true;
+ Label call_dispose = ig.DefineLabel ();
ig.BeginFinallyBlock ();
-
- disposable.EmitThis ();
+
enumerator.EmitThis ();
enumerator.EmitLoad ();
ig.Emit (OpCodes.Isinst, TypeManager.idisposable_type);
- disposable.EmitStore ();
- disposable.EmitLoad ();
- ig.Emit (OpCodes.Brfalse, end_finally);
- disposable.EmitThis ();
- disposable.EmitLoad ();
+ ig.Emit (OpCodes.Dup);
+ ig.Emit (OpCodes.Brtrue_S, call_dispose);
+ ig.Emit (OpCodes.Pop);
+ ig.Emit (OpCodes.Endfinally);
+
+ ig.MarkLabel (call_dispose);
ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void);
- ig.MarkLabel (end_finally);
- ec.InFinally = old_in_finally;
+
// The runtime generates this anyways.
// ig.Emit (OpCodes.Endfinally);
for (int i = 0; i < rank; i++)
args [i] = TypeManager.int32_type;
- ModuleBuilder mb = CodeGen.ModuleBuilder;
+ ModuleBuilder mb = CodeGen.Module.Builder;
get = mb.GetArrayMethod (
array_type, "Get",
CallingConventions.HasThis| CallingConventions.Standard,
ILGenerator ig = ec.ig;
Label old_begin = ec.LoopBegin, old_end = ec.LoopEnd;
- bool old_inloop = ec.InLoop;
- int old_loop_begin_try_catch_level = ec.LoopBeginTryCatchLevel;
ec.LoopBegin = ig.DefineLabel ();
ec.LoopEnd = ig.DefineLabel ();
- ec.InLoop = true;
- ec.LoopBeginTryCatchLevel = ec.TryCatchLevel;
if (hm != null)
EmitCollectionForeach (ec);
ec.LoopBegin = old_begin;
ec.LoopEnd = old_end;
- ec.InLoop = old_inloop;
- ec.LoopBeginTryCatchLevel = old_loop_begin_try_catch_level;
}
}
}