ec.ig.Emit (OpCodes.Pop);
}
}
+
+ public class ParenthesizedExpression : Expression
+ {
+ public Expression Expr;
+
+ public ParenthesizedExpression (Expression expr, Location loc)
+ {
+ this.Expr = expr;
+ this.loc = loc;
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ Expr = Expr.Resolve (ec);
+ return Expr;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ throw new Exception ("Should not happen");
+ }
+ }
/// <summary>
/// Unary expressions.
// For now: only localvariables when not remapped
//
- if (method == null &&
- (expr is LocalVariableReference && ec.RemapToProxy == false) ||
- (expr is FieldExpr && ((FieldExpr) expr).FieldInfo.IsStatic)){
+ if (method == null && (expr is FieldExpr && ((FieldExpr) expr).FieldInfo.IsStatic)){
if (empty_expr == null)
empty_expr = new EmptyExpression ();
Operator oper;
Expression left, right;
- //
- // After resolution, method might contain the operator overload
- // method.
- //
- protected MethodBase method;
- ArrayList Arguments;
-
- bool DelegateOperation;
-
// This must be kept in sync with Operator!!!
public static readonly string [] oper_names;
union = (MethodGroupExpr) left_expr;
if (union != null) {
- Arguments = new ArrayList ();
- Arguments.Add (new Argument (left, Argument.AType.Expression));
- Arguments.Add (new Argument (right, Argument.AType.Expression));
+ ArrayList args = new ArrayList (2);
+ args.Add (new Argument (left, Argument.AType.Expression));
+ args.Add (new Argument (right, Argument.AType.Expression));
- method = Invocation.OverloadResolve (ec, union, Arguments, Location.Null);
+ MethodBase method = Invocation.OverloadResolve (ec, union, args, Location.Null);
if (method != null) {
MethodInfo mi = (MethodInfo) method;
- type = mi.ReturnType;
- return this;
+ return new BinaryMethod (mi.ReturnType, method, args);
} else {
overload_failed = true;
}
//
if (l == TypeManager.string_type){
+ MethodBase method;
if (r == TypeManager.void_type) {
Error_OperatorCannotBeApplied ();
ls.Value + rs.Value);
}
- if (left is Binary){
- Binary b = (Binary) left;
+ if (left is BinaryMethod){
+ BinaryMethod b = (BinaryMethod) left;
//
// Call String.Concat (string, string, string) or
// String.Concat (string, string, string, string)
// if possible.
//
- if (b.oper == Operator.Addition &&
- (b.method == TypeManager.string_concat_string_string ||
- b.method == TypeManager.string_concat_string_string_string)){
+ if (b.method == TypeManager.string_concat_string_string ||
+ b.method == TypeManager.string_concat_string_string_string){
ArrayList bargs = b.Arguments;
int count = bargs.Count;
if (count == 2){
- Arguments = bargs;
- Arguments.Add (new Argument (right, Argument.AType.Expression));
- type = TypeManager.string_type;
- method = TypeManager.string_concat_string_string_string;
-
- return this;
+ bargs.Add (new Argument (right, Argument.AType.Expression));
+ return new BinaryMethod (
+ TypeManager.string_type,
+ TypeManager.string_concat_string_string_string, bargs);
} else if (count == 3){
- Arguments = bargs;
- Arguments.Add (new Argument (right, Argument.AType.Expression));
- type = TypeManager.string_type;
- method = TypeManager.string_concat_string_string_string_string;
- return this;
+ bargs.Add (new Argument (right, Argument.AType.Expression));
+ return new BinaryMethod (
+ TypeManager.string_type,
+ TypeManager.string_concat_string_string_string_string, bargs);
}
}
}
return null;
}
}
- type = TypeManager.string_type;
- Arguments = new ArrayList ();
- Arguments.Add (new Argument (left, Argument.AType.Expression));
- Arguments.Add (new Argument (right, Argument.AType.Expression));
+ //
+ // Cascading concats will hold up to 4 arguments
+ //
+ ArrayList args = new ArrayList (4);
+ args.Add (new Argument (left, Argument.AType.Expression));
+ args.Add (new Argument (right, Argument.AType.Expression));
- return this;
-
+ return new BinaryMethod (TypeManager.string_type, method, args);
} else if (r == TypeManager.string_type){
// object + string
return null;
}
- method = TypeManager.string_concat_object_object;
left = Convert.ImplicitConversion (ec, left, TypeManager.object_type, loc);
if (left == null){
Error_OperatorCannotBeApplied (loc, OperName (oper), l, r);
return null;
}
- Arguments = new ArrayList ();
- Arguments.Add (new Argument (left, Argument.AType.Expression));
- Arguments.Add (new Argument (right, Argument.AType.Expression));
+ ArrayList args = new ArrayList (2);
+ args.Add (new Argument (left, Argument.AType.Expression));
+ args.Add (new Argument (right, Argument.AType.Expression));
- type = TypeManager.string_type;
-
- return this;
+ return new BinaryMethod (TypeManager.string_type, TypeManager.string_concat_object_object, args);
}
//
if (oper == Operator.Addition || oper == Operator.Subtraction) {
if (l.IsSubclassOf (TypeManager.delegate_type) &&
r.IsSubclassOf (TypeManager.delegate_type)) {
+ MethodInfo method;
+ ArrayList args = new ArrayList (2);
- Arguments = new ArrayList ();
- Arguments.Add (new Argument (left, Argument.AType.Expression));
- Arguments.Add (new Argument (right, Argument.AType.Expression));
+ args = new ArrayList (2);
+ args.Add (new Argument (left, Argument.AType.Expression));
+ args.Add (new Argument (right, Argument.AType.Expression));
if (oper == Operator.Addition)
method = TypeManager.delegate_combine_delegate_delegate;
return null;
}
- DelegateOperation = true;
- type = l;
- return this;
+ return new BinaryDelegate (l, method, args);
}
//
public override Expression DoResolve (EmitContext ec)
{
- left = left.Resolve (ec);
+ if ((oper == Operator.Subtraction) && (left is ParenthesizedExpression)) {
+ left = ((ParenthesizedExpression) left).Expr;
+ left = left.Resolve (ec, ResolveFlags.VariableOrValue | ResolveFlags.Type);
+ if (left == null)
+ return null;
+
+ if (left.eclass == ExprClass.Type) {
+ Error (75, "Casting a negative value needs to have the value in parentheses.");
+ return null;
+ }
+ } else
+ left = left.Resolve (ec);
right = right.Resolve (ec);
if (left == null || right == null)
/// </remarks>
public bool EmitBranchable (EmitContext ec, Label target, bool onTrue)
{
- if (method != null)
- return false;
-
ILGenerator ig = ec.ig;
//
Type r = right.Type;
OpCode opcode;
- if (method != null) {
-
- // Note that operators are static anyway
-
- if (Arguments != null)
- Invocation.EmitArguments (ec, method, Arguments);
-
- if (method is MethodInfo)
- ig.Emit (OpCodes.Call, (MethodInfo) method);
- else
- ig.Emit (OpCodes.Call, (ConstructorInfo) method);
-
- if (DelegateOperation)
- ig.Emit (OpCodes.Castclass, type);
-
- return;
- }
-
//
// Handle short-circuit operators differently
// than the rest
ig.Emit (opcode);
}
+ }
+
+ //
+ // Object created by Binary when the binary operator uses an method instead of being
+ // a binary operation that maps to a CIL binary operation.
+ //
+ public class BinaryMethod : Expression {
+ public MethodBase method;
+ public ArrayList Arguments;
+
+ public BinaryMethod (Type t, MethodBase m, ArrayList args)
+ {
+ method = m;
+ Arguments = args;
+ type = t;
+ eclass = ExprClass.Value;
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ return this;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ ILGenerator ig = ec.ig;
+
+ if (Arguments != null)
+ Invocation.EmitArguments (ec, method, Arguments);
+
+ if (method is MethodInfo)
+ ig.Emit (OpCodes.Call, (MethodInfo) method);
+ else
+ ig.Emit (OpCodes.Call, (ConstructorInfo) method);
+ }
+ }
+
+ //
+ // Object created with +/= on delegates
+ //
+ public class BinaryDelegate : Expression {
+ MethodInfo method;
+ ArrayList args;
+
+ public BinaryDelegate (Type t, MethodInfo mi, ArrayList args)
+ {
+ method = mi;
+ this.args = args;
+ type = t;
+ eclass = ExprClass.Value;
+ }
+
+ public override Expression DoResolve (EmitContext ec)
+ {
+ return this;
+ }
- public bool IsBuiltinOperator {
+ public override void Emit (EmitContext ec)
+ {
+ ILGenerator ig = ec.ig;
+
+ Invocation.EmitArguments (ec, method, args);
+
+ ig.Emit (OpCodes.Call, (MethodInfo) method);
+ ig.Emit (OpCodes.Castclass, type);
+ }
+
+ public Expression Right {
get {
- return method == null;
+ Argument arg = (Argument) args [1];
+ return arg.Expr;
}
}
- }
+ public bool IsAddition {
+ get {
+ return method == TypeManager.delegate_combine_delegate_delegate;
+ }
+ }
+ }
+
//
// User-defined conditional logical operator
public class ConditionalLogicalOperator : Expression {
if ((variable_info != null) && !variable_info.IsAssigned (ec, loc))
return null;
+ if (local_info.LocalBuilder == null)
+ return ec.RemapLocal (local_info);
+
return this;
}
Error (1604, "cannot assign to `" + Name + "' because it is readonly");
return null;
}
+
+ if (local_info.LocalBuilder == null)
+ return ec.RemapLocalLValue (local_info, right_side);
return this;
}
{
ILGenerator ig = ec.ig;
- if (local_info.LocalBuilder == null){
- ig.Emit (OpCodes.Ldarg_0);
- ig.Emit (OpCodes.Ldfld, local_info.FieldBuilder);
- } else
- ig.Emit (OpCodes.Ldloc, local_info.LocalBuilder);
-
- local_info.Used = true;
+ ig.Emit (OpCodes.Ldloc, local_info.LocalBuilder);
}
public void EmitAssign (EmitContext ec, Expression source)
local_info.Assigned = true;
- if (local_info.LocalBuilder == null){
- ig.Emit (OpCodes.Ldarg_0);
- source.Emit (ec);
- ig.Emit (OpCodes.Stfld, local_info.FieldBuilder);
- } else {
- source.Emit (ec);
- ig.Emit (OpCodes.Stloc, local_info.LocalBuilder);
- }
+ source.Emit (ec);
+ ig.Emit (OpCodes.Stloc, local_info.LocalBuilder);
}
public void AddressOf (EmitContext ec, AddressOp mode)
{
ILGenerator ig = ec.ig;
- if (local_info.LocalBuilder == null){
- ig.Emit (OpCodes.Ldarg_0);
- ig.Emit (OpCodes.Ldflda, local_info.FieldBuilder);
- } else
- ig.Emit (OpCodes.Ldloca, local_info.LocalBuilder);
+ ig.Emit (OpCodes.Ldloca, local_info.LocalBuilder);
}
public override string ToString ()
if (is_out && ec.DoFlowAnalysis && !IsAssigned (ec, loc))
return null;
+ if (ec.RemapToProxy)
+ return ec.RemapParameter (idx);
+
return this;
}
SetAssigned (ec);
+ if (ec.RemapToProxy)
+ return ec.RemapParameterLValue (idx, right_side);
+
return this;
}
{
ILGenerator ig = ec.ig;
- if (ec.RemapToProxy){
- ig.Emit (OpCodes.Ldarg_0);
- ec.EmitArgument (idx);
- return;
- }
-
int arg_idx = idx;
if (!ec.IsStatic)
{
ILGenerator ig = ec.ig;
- if (ec.RemapToProxy){
- ig.Emit (OpCodes.Ldarg_0);
- source.Emit (ec);
- ec.EmitStoreArgument (idx);
- return;
- }
-
int arg_idx = idx;
if (!ec.IsStatic)
public void AddressOf (EmitContext ec, AddressOp mode)
{
- if (ec.RemapToProxy){
- Report.Error (-1, "Report this: Taking the address of a remapped parameter not supported");
- return;
- }
-
int arg_idx = idx;
if (!ec.IsStatic)
}
/// <summary>
- /// Determines "better conversion" as specified in 7.4.2.3
- /// Returns : 1 if a->p is better
- /// 0 if a->q or neither is better
+ /// Determines "better conversion" as specified in 7.4.2.3
+ ///
+ /// Returns : 1 if a->p is better
+ /// 0 if a->q or neither is better
/// </summary>
static int BetterConversion (EmitContext ec, Argument a, Type p, Type q, Location loc)
{
Expression argument_expr = a.Expr;
if (argument_type == null)
- throw new Exception ("Expression of type " + a.Expr + " does not resolve its type");
+ throw new Exception ("Expression of type " + a.Expr +
+ " does not resolve its type");
//
// This is a special case since csc behaves this way. I can't find
// it anywhere in the spec but oh well ...
//
- if (argument_expr is NullLiteral && p == TypeManager.string_type && q == TypeManager.object_type)
+ if (argument_expr is NullLiteral &&
+ p == TypeManager.string_type &&
+ q == TypeManager.object_type)
return 1;
- else if (argument_expr is NullLiteral && p == TypeManager.object_type && q == TypeManager.string_type)
+ else if (argument_expr is NullLiteral &&
+ p == TypeManager.object_type &&
+ q == TypeManager.string_type)
return 0;
if (p == q)
}
/// <summary>
- /// Determines "Better function"
+ /// Determines "Better function" between candidate
+ /// and the current best match
/// </summary>
/// <remarks>
- /// and returns an integer indicating :
- /// 0 if candidate ain't better
- /// 1 if candidate is better than the current best match
+ /// Returns an integer indicating :
+ /// 0 if candidate ain't better
+ /// 1 if candidate is better than the current best match
/// </remarks>
static int BetterFunction (EmitContext ec, ArrayList args,
- MethodBase candidate, MethodBase best,
- bool expanded_form, Location loc)
+ MethodBase candidate, bool candidate_params,
+ MethodBase best, bool best_params,
+ Location loc)
{
ParameterData candidate_pd = GetParameterData (candidate);
ParameterData best_pd;
if (candidate_pd.ParameterModifier (cand_count - 1) != Parameter.Modifier.PARAMS)
if (cand_count != argument_count)
return 0;
-
+
if (best == null) {
int x = 0;
candidate_pd.ParameterModifier (cand_count - 1) == Parameter.Modifier.PARAMS)
return 1;
- for (int j = argument_count; j > 0;) {
- j--;
+ for (int j = 0; j < argument_count; ++j) {
Argument a = (Argument) args [j];
Type t = candidate_pd.ParameterType (j);
if (candidate_pd.ParameterModifier (j) == Parameter.Modifier.PARAMS)
- if (expanded_form)
+ if (candidate_params)
t = TypeManager.GetElementType (t);
x = BetterConversion (ec, a, t, null, loc);
Type bt = best_pd.ParameterType (j);
if (candidate_pd.ParameterModifier (j) == Parameter.Modifier.PARAMS)
- if (expanded_form)
+ if (candidate_params)
ct = TypeManager.GetElementType (ct);
if (best_pd.ParameterModifier (j) == Parameter.Modifier.PARAMS)
- if (expanded_form)
+ if (best_params)
bt = TypeManager.GetElementType (bt);
-
+
x = BetterConversion (ec, a, ct, bt, loc);
y = BetterConversion (ec, a, bt, ct, loc);
rating2 += y;
}
+ //
+ // If a method (in the normal form) with the
+ // same signature as the expanded form of the
+ // current best params method already exists,
+ // the expanded form is not applicable so we
+ // force it to select the candidate
+ //
+ if (!candidate_params && best_params && cand_count == argument_count)
+ return 1;
+
if (rating1 > rating2)
return 1;
else
MemberInfo [] miset;
MethodGroupExpr union;
- if (mg1 == null){
+ if (mg1 == null) {
if (mg2 == null)
return null;
return (MethodGroupExpr) mg2;
ArrayList common = new ArrayList ();
- foreach (MethodBase l in left_set.Methods){
- foreach (MethodBase r in right_set.Methods){
- if (l != r)
- continue;
+ foreach (MethodBase r in right_set.Methods){
+ if (TypeManager.ArrayContainsMethod (left_set.Methods, r))
common.Add (r);
- break;
- }
}
-
+
miset = new MemberInfo [length1 + length2 - common.Count];
left_set.Methods.CopyTo (miset, 0);
int k = length1;
- foreach (MemberInfo mi in right_set.Methods){
- if (!common.Contains (mi))
- miset [k++] = mi;
+ foreach (MethodBase r in right_set.Methods) {
+ if (!common.Contains (r))
+ miset [k++] = r;
}
-
+
union = new MethodGroupExpr (miset, loc);
return union;
}
/// <summary>
- /// Determines is the candidate method, if a params method, is applicable
- /// in its expanded form to the given set of arguments
+ /// Determines if the candidate method, if a params method, is applicable
+ /// in its expanded form to the given set of arguments
/// </summary>
static bool IsParamsMethodApplicable (EmitContext ec, ArrayList arguments, MethodBase candidate)
{
return true;
//
- // If we have come this far, the case which remains is when the number of parameters
- // is less than or equal to the argument count.
+ // If we have come this far, the case which
+ // remains is when the number of parameters is
+ // less than or equal to the argument count.
//
for (int i = 0; i < pd_count - 1; ++i) {
if (a_mod == p_mod) {
if (a_mod == Parameter.Modifier.NONE)
- if (!Convert.ImplicitConversionExists (ec, a.Expr, pd.ParameterType (i)))
+ if (!Convert.ImplicitConversionExists (ec,
+ a.Expr,
+ pd.ParameterType (i)))
return false;
if ((a_mod & Parameter.Modifier.ISBYREF) != 0) {
for (int i = pd_count - 1; i < arg_count; i++) {
Argument a = (Argument) arguments [i];
- if (!Convert.ImplicitStandardConversionExists (a.Expr, element_type))
+ if (!Convert.ImplicitConversionExists (ec, a.Expr, element_type))
return false;
}
}
/// <summary>
- /// Determines if the candidate method is applicable (section 14.4.2.1)
- /// to the given set of arguments
+ /// Determines if the candidate method is applicable (section 14.4.2.1)
+ /// to the given set of arguments
/// </summary>
static bool IsApplicable (EmitContext ec, ArrayList arguments, MethodBase candidate)
{
if (a_mod == p_mod ||
(a_mod == Parameter.Modifier.NONE && p_mod == Parameter.Modifier.PARAMS)) {
if (a_mod == Parameter.Modifier.NONE) {
- if (!Convert.ImplicitConversionExists (ec,
- a.Expr, pd.ParameterType (i)))
+ if (!Convert.ImplicitConversionExists (ec,
+ a.Expr,
+ pd.ParameterType (i)))
return false;
}
if (!pt.IsByRef)
pt = TypeManager.GetReferenceType (pt);
-
+
if (pt != a.Type)
return false;
}
ArrayList candidates = new ArrayList ();
//
- // First we construct the set of applicable methods
+ // Used to keep a map between the candidate
+ // and whether it is being considered in its
+ // normal or expanded form
//
+ Hashtable candidate_to_form = new PtrHashtable ();
+
+ //
+ // First we construct the set of applicable methods
//
// We start at the top of the type hierarchy and
// go down to find applicable methods
return null;
}
-
bool found_applicable = false;
foreach (MethodBase candidate in me.Methods) {
Type decl_type = candidate.DeclaringType;
// Check if candidate is applicable (section 14.4.2.1)
- if (!IsApplicable (ec, Arguments, candidate))
- continue;
-
-
- candidates.Add (candidate);
- applicable_type = candidate.DeclaringType;
- found_applicable = true;
-
+ if (!IsApplicable (ec, Arguments, candidate)) {
+ // Candidate is applicable in normal form
+ candidates.Add (candidate);
+ applicable_type = candidate.DeclaringType;
+ found_applicable = true;
+ candidate_to_form [candidate] = false;
+ } else {
+ if (IsParamsMethodApplicable (ec, Arguments, candidate)) {
+ // Candidate is applicable in expanded form
+ candidates.Add (candidate);
+ applicable_type = candidate.DeclaringType;
+ found_applicable = true;
+ candidate_to_form [candidate] = true;
+ }
+ }
}
-
//
// Now we actually find the best method
//
foreach (MethodBase candidate in candidates) {
- int x = BetterFunction (ec, Arguments, candidate, method, false, loc);
+ bool cand_params = (bool) candidate_to_form [candidate];
+ bool method_params = false;
+
+ if (method != null)
+ method_params = (bool) candidate_to_form [method];
+ int x = BetterFunction (ec, Arguments,
+ candidate, cand_params,
+ method, method_params,
+ loc);
if (x == 0)
continue;
method = candidate;
}
-
if (Arguments == null)
argument_count = 0;
else
argument_count = Arguments.Count;
- //
- // Now we see if we can find params functions,
- // applicable in their expanded form since if
- // they were applicable in their normal form,
- // they would have been selected above anyways
- //
- bool chose_params_expanded = false;
-
- if (method == null) {
- candidates = new ArrayList ();
- foreach (MethodBase candidate in me.Methods){
- if (!IsParamsMethodApplicable (ec, Arguments, candidate))
- continue;
-
- candidates.Add (candidate);
-
- int x = BetterFunction (ec, Arguments, candidate, method, true, loc);
- if (x == 0)
- continue;
-
- method = candidate;
- chose_params_expanded = true;
- }
- }
if (method == null) {
//
VerifyArgumentsCompat (ec, Arguments, argument_count, c, false,
null, loc);
+ break;
}
if (!Location.IsNull (loc)) {
// Now check that there are no ambiguities i.e the selected method
// should be better than all the others
//
+ bool best_params = (bool) candidate_to_form [method];
foreach (MethodBase candidate in candidates){
- if (candidate == method)
- continue;
+ if (candidate == method)
+ continue;
+
//
// If a normal method is applicable in
// the sense that it has the same
// applicable so we debar the params
// method.
//
-
- if (IsParamsMethodApplicable (ec, Arguments, candidate) &&
- IsApplicable (ec, Arguments, method))
- continue;
-
- int x = BetterFunction (ec, Arguments, method, candidate,
- chose_params_expanded, loc);
+ if ((IsParamsMethodApplicable (ec, Arguments, candidate) &&
+ IsApplicable (ec, Arguments, method)))
+ continue;
+
+ bool cand_params = (bool) candidate_to_form [candidate];
+ int x = BetterFunction (ec, Arguments,
+ method, best_params,
+ candidate, cand_params,
+ loc);
if (x != 1) {
Report.Error (
// necessary etc. and return if everything is
// all right
//
-
- if (!VerifyArgumentsCompat (ec, Arguments, argument_count, method,
- chose_params_expanded, null, loc))
+ if (!VerifyArgumentsCompat (ec, Arguments, argument_count, method,
+ best_params, null, loc))
return null;
return method;
if (a_mod != p_mod &&
pd.ParameterModifier (pd_count - 1) != Parameter.Modifier.PARAMS) {
if (!Location.IsNull (loc)) {
- Console.WriteLine ("A:P: " + a.GetParameterModifier ());
- Console.WriteLine ("PP:: " + pd.ParameterModifier (j));
- Console.WriteLine ("PT: " + parameter_type.IsByRef);
Report.Error (1502, loc,
"The best overloaded match for method '" + FullMethodDesc (method)+
"' has some invalid arguments");
}
}
+ //
+ // This produces the value that renders an instance, used by the iterators code
+ //
+ public class ProxyInstance : Expression, IMemoryLocation {
+ public override Expression DoResolve (EmitContext ec)
+ {
+ eclass = ExprClass.Variable;
+ type = ec.ContainerType;
+ return this;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ ec.ig.Emit (OpCodes.Ldarg_0);
+
+ }
+
+ public void AddressOf (EmitContext ec, AddressOp mode)
+ {
+ ec.ig.Emit (OpCodes.Ldarg_0);
+ }
+ }
+
/// <summary>
/// Implements the typeof operator
/// </summary>
return false;
}
- ec.StartFlowBranching (FlowBranchingType.BLOCK, loc);
+ ec.StartFlowBranching (FlowBranching.BranchingType.Block, loc);
if (!TrueStatement.Resolve (ec)) {
ec.KillFlowBranching ();
return false;
}
- ec.CurrentBranching.CreateSibling ();
+ ec.CurrentBranching.CreateSibling (FlowBranching.SiblingType.Conditional);
if ((FalseStatement != null) && !FalseStatement.Resolve (ec)) {
ec.KillFlowBranching ();
{
bool ok = true;
- ec.StartFlowBranching (FlowBranchingType.LOOP_BLOCK, loc);
+ ec.StartFlowBranching (FlowBranching.BranchingType.LoopBlock, loc);
if (!EmbeddedStatement.Resolve (ec))
ok = false;
}
ec.CurrentBranching.Infinite = infinite;
- FlowReturns returns = ec.EndFlowBranching ();
- may_return = returns != FlowReturns.NEVER;
+ FlowBranching.FlowReturns returns = ec.EndFlowBranching ();
+ may_return = returns != FlowBranching.FlowReturns.Never;
return ok;
}
if (expr == null)
return false;
- ec.StartFlowBranching (FlowBranchingType.LOOP_BLOCK, loc);
+ ec.StartFlowBranching (FlowBranching.BranchingType.LoopBlock, loc);
//
// Inform whether we are infinite or not
//
// We are not infinite, so the loop may or may not be executed.
//
- ec.CurrentBranching.CreateSibling ();
+ ec.CurrentBranching.CreateSibling (FlowBranching.SiblingType.Conditional);
}
if (!Statement.Resolve (ec))
ec.KillFlowBranching ();
else {
ec.CurrentBranching.Infinite = infinite;
- FlowReturns returns = ec.EndFlowBranching ();
- may_return = returns != FlowReturns.NEVER;
+ FlowBranching.FlowReturns returns = ec.EndFlowBranching ();
+ may_return = returns != FlowBranching.FlowReturns.Never;
}
return ok;
} else
infinite = true;
- ec.StartFlowBranching (FlowBranchingType.LOOP_BLOCK, loc);
+ ec.StartFlowBranching (FlowBranching.BranchingType.LoopBlock, loc);
if (!infinite)
- ec.CurrentBranching.CreateSibling ();
+ ec.CurrentBranching.CreateSibling (FlowBranching.SiblingType.Conditional);
if (!Statement.Resolve (ec))
ok = false;
ec.KillFlowBranching ();
else {
ec.CurrentBranching.Infinite = infinite;
- FlowReturns returns = ec.EndFlowBranching ();
- may_return = returns != FlowReturns.NEVER;
+ FlowBranching.FlowReturns returns = ec.EndFlowBranching ();
+ may_return = returns != FlowBranching.FlowReturns.Never;
}
return ok;
else
vector.CheckOutParameters (ec.CurrentBranching);
- vector.Returns = FlowReturns.ALWAYS;
- vector.Breaks = FlowReturns.ALWAYS;
+ vector.Returns = FlowBranching.FlowReturns.Always;
+ vector.Breaks = FlowBranching.FlowReturns.Always;
return true;
}
if (!label.IsDefined)
label.AddUsageVector (ec.CurrentBranching.CurrentUsageVector);
- ec.CurrentBranching.CurrentUsageVector.Breaks = FlowReturns.ALWAYS;
- ec.CurrentBranching.CurrentUsageVector.Returns = FlowReturns.ALWAYS;
+ ec.CurrentBranching.CurrentUsageVector.Breaks = FlowBranching.FlowReturns.Always;
+ ec.CurrentBranching.CurrentUsageVector.Returns = FlowBranching.FlowReturns.Always;
return true;
}
if (vectors != null)
ec.CurrentBranching.CurrentUsageVector.MergeJumpOrigins (vectors);
else {
- ec.CurrentBranching.CurrentUsageVector.Breaks = FlowReturns.NEVER;
- ec.CurrentBranching.CurrentUsageVector.Returns = FlowReturns.NEVER;
+ ec.CurrentBranching.CurrentUsageVector.Breaks = FlowBranching.FlowReturns.Never;
+ ec.CurrentBranching.CurrentUsageVector.Returns = FlowBranching.FlowReturns.Never;
}
referenced = true;
public override bool Resolve (EmitContext ec)
{
- ec.CurrentBranching.CurrentUsageVector.Breaks = FlowReturns.ALWAYS;
- ec.CurrentBranching.CurrentUsageVector.Returns = FlowReturns.ALWAYS;
+ ec.CurrentBranching.CurrentUsageVector.Breaks = FlowBranching.FlowReturns.Always;
+ ec.CurrentBranching.CurrentUsageVector.Returns = FlowBranching.FlowReturns.Always;
return true;
}
label = sl.ILLabelCode;
- ec.CurrentBranching.CurrentUsageVector.Breaks = FlowReturns.UNREACHABLE;
- ec.CurrentBranching.CurrentUsageVector.Returns = FlowReturns.ALWAYS;
+ ec.CurrentBranching.CurrentUsageVector.Breaks = FlowBranching.FlowReturns.Unreachable;
+ ec.CurrentBranching.CurrentUsageVector.Returns = FlowBranching.FlowReturns.Always;
return true;
}
}
}
- ec.CurrentBranching.CurrentUsageVector.Returns = FlowReturns.EXCEPTION;
- ec.CurrentBranching.CurrentUsageVector.Breaks = FlowReturns.EXCEPTION;
+ ec.CurrentBranching.CurrentUsageVector.Returns = FlowBranching.FlowReturns.Exception;
+ ec.CurrentBranching.CurrentUsageVector.Breaks = FlowBranching.FlowReturns.Exception;
return true;
}
public override bool Resolve (EmitContext ec)
{
ec.CurrentBranching.MayLeaveLoop = true;
- ec.CurrentBranching.CurrentUsageVector.Breaks = FlowReturns.ALWAYS;
+ ec.CurrentBranching.CurrentUsageVector.Breaks = FlowBranching.FlowReturns.Always;
return true;
}
public override bool Resolve (EmitContext ec)
{
- ec.CurrentBranching.CurrentUsageVector.Breaks = FlowReturns.ALWAYS;
+ ec.CurrentBranching.CurrentUsageVector.Breaks = FlowBranching.FlowReturns.Always;
return true;
}
}
}
- // <summary>
- // This is used in the control flow analysis code to specify whether the
- // current code block may return to its enclosing block before reaching
- // its end.
- // </summary>
- public enum FlowReturns {
- // It can never return.
- NEVER,
-
- // This means that the block contains a conditional return statement
- // somewhere.
- SOMETIMES,
-
- // The code always returns, ie. there's an unconditional return / break
- // statement in it.
- ALWAYS,
-
- // The code always throws an exception.
- EXCEPTION,
-
- // The current code block is unreachable. This happens if it's immediately
- // following a FlowReturns.ALWAYS block.
- UNREACHABLE
- }
-
- // <summary>
- // This is a special bit vector which can inherit from another bit vector doing a
- // copy-on-write strategy. The inherited vector may have a smaller size than the
- // current one.
- // </summary>
- public class MyBitVector {
- public readonly int Count;
- public readonly MyBitVector InheritsFrom;
-
- bool is_dirty;
- BitArray vector;
-
- public MyBitVector (int Count)
- : this (null, Count)
- { }
-
- public MyBitVector (MyBitVector InheritsFrom, int Count)
- {
- this.InheritsFrom = InheritsFrom;
- this.Count = Count;
- }
-
- // <summary>
- // Checks whether this bit vector has been modified. After setting this to true,
- // we won't use the inherited vector anymore, but our own copy of it.
- // </summary>
- public bool IsDirty {
- get {
- return is_dirty;
- }
-
- set {
- if (!is_dirty)
- initialize_vector ();
- }
- }
-
- // <summary>
- // Get/set bit `index' in the bit vector.
- // </summary>
- public bool this [int index]
- {
- get {
- if (index > Count)
- throw new ArgumentOutOfRangeException ();
-
- // We're doing a "copy-on-write" strategy here; as long
- // as nobody writes to the array, we can use our parent's
- // copy instead of duplicating the vector.
-
- if (vector != null)
- return vector [index];
- else if (InheritsFrom != null) {
- BitArray inherited = InheritsFrom.Vector;
-
- if (index < inherited.Count)
- return inherited [index];
- else
- return false;
- } else
- return false;
- }
-
- set {
- if (index > Count)
- throw new ArgumentOutOfRangeException ();
-
- // Only copy the vector if we're actually modifying it.
-
- if (this [index] != value) {
- initialize_vector ();
-
- vector [index] = value;
- }
- }
- }
-
- // <summary>
- // If you explicitly convert the MyBitVector to a BitArray, you will get a deep
- // copy of the bit vector.
- // </summary>
- public static explicit operator BitArray (MyBitVector vector)
- {
- vector.initialize_vector ();
- return vector.Vector;
- }
-
- // <summary>
- // Performs an `or' operation on the bit vector. The `new_vector' may have a
- // different size than the current one.
- // </summary>
- public void Or (MyBitVector new_vector)
- {
- BitArray new_array = new_vector.Vector;
-
- initialize_vector ();
-
- int upper;
- if (vector.Count < new_array.Count)
- upper = vector.Count;
- else
- upper = new_array.Count;
-
- for (int i = 0; i < upper; i++)
- vector [i] = vector [i] | new_array [i];
- }
-
- // <summary>
- // Perfonrms an `and' operation on the bit vector. The `new_vector' may have
- // a different size than the current one.
- // </summary>
- public void And (MyBitVector new_vector)
- {
- BitArray new_array = new_vector.Vector;
-
- initialize_vector ();
-
- int lower, upper;
- if (vector.Count < new_array.Count)
- lower = upper = vector.Count;
- else {
- lower = new_array.Count;
- upper = vector.Count;
- }
-
- for (int i = 0; i < lower; i++)
- vector [i] = vector [i] & new_array [i];
-
- for (int i = lower; i < upper; i++)
- vector [i] = false;
- }
-
- // <summary>
- // This does a deep copy of the bit vector.
- // </summary>
- public MyBitVector Clone ()
- {
- MyBitVector retval = new MyBitVector (Count);
-
- retval.Vector = Vector;
-
- return retval;
- }
-
- BitArray Vector {
- get {
- if (vector != null)
- return vector;
- else if (!is_dirty && (InheritsFrom != null))
- return InheritsFrom.Vector;
-
- initialize_vector ();
-
- return vector;
- }
-
- set {
- initialize_vector ();
-
- for (int i = 0; i < System.Math.Min (vector.Count, value.Count); i++)
- vector [i] = value [i];
- }
- }
-
- void initialize_vector ()
- {
- if (vector != null)
- return;
-
- vector = new BitArray (Count, false);
- if (InheritsFrom != null)
- Vector = InheritsFrom.Vector;
-
- is_dirty = true;
- }
-
- public override string ToString ()
- {
- StringBuilder sb = new StringBuilder ("MyBitVector (");
-
- BitArray vector = Vector;
- sb.Append (Count);
- sb.Append (",");
- if (!IsDirty)
- sb.Append ("INHERITED - ");
- for (int i = 0; i < vector.Count; i++) {
- if (i > 0)
- sb.Append (",");
- sb.Append (vector [i]);
- }
-
- sb.Append (")");
- return sb.ToString ();
- }
- }
-
- // <summary>
- // The type of a FlowBranching.
- // </summary>
- public enum FlowBranchingType {
- // Normal (conditional or toplevel) block.
- BLOCK,
-
- // A loop block.
- LOOP_BLOCK,
-
- // Try/Catch block.
- EXCEPTION,
-
- // Switch block.
- SWITCH,
-
- // Switch section.
- SWITCH_SECTION
- }
-
- // <summary>
- // A new instance of this class is created every time a new block is resolved
- // and if there's branching in the block's control flow.
- // </summary>
- public class FlowBranching {
- // <summary>
- // The type of this flow branching.
- // </summary>
- public readonly FlowBranchingType Type;
-
- // <summary>
- // The block this branching is contained in. This may be null if it's not
- // a top-level block and it doesn't declare any local variables.
- // </summary>
- public readonly Block Block;
-
- // <summary>
- // The parent of this branching or null if this is the top-block.
- // </summary>
- public readonly FlowBranching Parent;
-
- // <summary>
- // Start-Location of this flow branching.
- // </summary>
- public readonly Location Location;
-
- // <summary>
- // A list of UsageVectors. A new vector is added each time control flow may
- // take a different path.
- // </summary>
- public UsageVector[] Siblings;
-
- // <summary>
- // If this is an infinite loop.
- // </summary>
- public bool Infinite;
-
- // <summary>
- // If we may leave the current loop.
- // </summary>
- public bool MayLeaveLoop;
-
- //
- // Private
- //
- VariableMap param_map, local_map;
- ArrayList finally_vectors;
-
- static int next_id = 0;
- int id;
-
- // <summary>
- // Performs an `And' operation on the FlowReturns status
- // (for instance, a block only returns ALWAYS if all its siblings
- // always return).
- // </summary>
- public static FlowReturns AndFlowReturns (FlowReturns a, FlowReturns b)
- {
- if (b == FlowReturns.UNREACHABLE)
- return a;
-
- switch (a) {
- case FlowReturns.NEVER:
- if (b == FlowReturns.NEVER)
- return FlowReturns.NEVER;
- else
- return FlowReturns.SOMETIMES;
-
- case FlowReturns.SOMETIMES:
- return FlowReturns.SOMETIMES;
-
- case FlowReturns.ALWAYS:
- if ((b == FlowReturns.ALWAYS) || (b == FlowReturns.EXCEPTION))
- return FlowReturns.ALWAYS;
- else
- return FlowReturns.SOMETIMES;
-
- case FlowReturns.EXCEPTION:
- if (b == FlowReturns.EXCEPTION)
- return FlowReturns.EXCEPTION;
- else if (b == FlowReturns.ALWAYS)
- return FlowReturns.ALWAYS;
- else
- return FlowReturns.SOMETIMES;
- }
-
- return b;
- }
-
- // <summary>
- // The vector contains a BitArray with information about which local variables
- // and parameters are already initialized at the current code position.
- // </summary>
- public class UsageVector {
- // <summary>
- // If this is true, then the usage vector has been modified and must be
- // merged when we're done with this branching.
- // </summary>
- public bool IsDirty;
-
- // <summary>
- // The number of parameters in this block.
- // </summary>
- public readonly int CountParameters;
-
- // <summary>
- // The number of locals in this block.
- // </summary>
- public readonly int CountLocals;
-
- // <summary>
- // If not null, then we inherit our state from this vector and do a
- // copy-on-write. If null, then we're the first sibling in a top-level
- // block and inherit from the empty vector.
- // </summary>
- public readonly UsageVector InheritsFrom;
-
- //
- // Private.
- //
- MyBitVector locals, parameters;
- FlowReturns real_returns, real_breaks;
- bool is_finally;
-
- static int next_id = 0;
- int id;
-
- //
- // Normally, you should not use any of these constructors.
- //
- public UsageVector (UsageVector parent, int num_params, int num_locals)
- {
- this.InheritsFrom = parent;
- this.CountParameters = num_params;
- this.CountLocals = num_locals;
- this.real_returns = FlowReturns.NEVER;
- this.real_breaks = FlowReturns.NEVER;
-
- if (parent != null) {
- locals = new MyBitVector (parent.locals, CountLocals);
- if (num_params > 0)
- parameters = new MyBitVector (parent.parameters, num_params);
- real_returns = parent.Returns;
- real_breaks = parent.Breaks;
- } else {
- locals = new MyBitVector (null, CountLocals);
- if (num_params > 0)
- parameters = new MyBitVector (null, num_params);
- }
-
- id = ++next_id;
- }
-
- public UsageVector (UsageVector parent)
- : this (parent, parent.CountParameters, parent.CountLocals)
- { }
-
- // <summary>
- // This does a deep copy of the usage vector.
- // </summary>
- public UsageVector Clone ()
- {
- UsageVector retval = new UsageVector (null, CountParameters, CountLocals);
-
- retval.locals = locals.Clone ();
- if (parameters != null)
- retval.parameters = parameters.Clone ();
- retval.real_returns = real_returns;
- retval.real_breaks = real_breaks;
-
- return retval;
- }
-
- public bool IsAssigned (VariableInfo var)
- {
- if (!var.IsParameter && AlwaysBreaks)
- return true;
-
- return var.IsAssigned (var.IsParameter ? parameters : locals);
- }
-
- public void SetAssigned (VariableInfo var)
- {
- if (!var.IsParameter && AlwaysBreaks)
- return;
-
- var.SetAssigned (var.IsParameter ? parameters : locals);
- }
-
- public bool IsFieldAssigned (VariableInfo var, string name)
- {
- if (!var.IsParameter && AlwaysBreaks)
- return true;
-
- return var.IsFieldAssigned (var.IsParameter ? parameters : locals, name);
- }
-
- public void SetFieldAssigned (VariableInfo var, string name)
- {
- if (!var.IsParameter && AlwaysBreaks)
- return;
-
- var.SetFieldAssigned (var.IsParameter ? parameters : locals, name);
- }
-
- // <summary>
- // Specifies when the current block returns.
- // If this is FlowReturns.UNREACHABLE, then control can never reach the
- // end of the method (so that we don't need to emit a return statement).
- // The same applies for FlowReturns.EXCEPTION, but in this case the return
- // value will never be used.
- // </summary>
- public FlowReturns Returns {
- get {
- return real_returns;
- }
-
- set {
- real_returns = value;
- }
- }
-
- // <summary>
- // Specifies whether control may return to our containing block
- // before reaching the end of this block. This happens if there
- // is a break/continue/goto/return in it.
- // This can also be used to find out whether the statement immediately
- // following the current block may be reached or not.
- // </summary>
- public FlowReturns Breaks {
- get {
- return real_breaks;
- }
-
- set {
- real_breaks = value;
- }
- }
-
- public bool AlwaysBreaks {
- get {
- return (Breaks == FlowReturns.ALWAYS) ||
- (Breaks == FlowReturns.EXCEPTION) ||
- (Breaks == FlowReturns.UNREACHABLE);
- }
- }
-
- public bool MayBreak {
- get {
- return Breaks != FlowReturns.NEVER;
- }
- }
-
- public bool AlwaysReturns {
- get {
- return (Returns == FlowReturns.ALWAYS) ||
- (Returns == FlowReturns.EXCEPTION);
- }
- }
-
- public bool MayReturn {
- get {
- return (Returns == FlowReturns.SOMETIMES) ||
- (Returns == FlowReturns.ALWAYS);
- }
- }
-
- // <summary>
- // Merge a child branching.
- // </summary>
- public FlowReturns MergeChildren (FlowBranching branching, UsageVector[] children)
- {
- MyBitVector new_locals = null;
- MyBitVector new_params = null;
-
- FlowReturns new_returns = FlowReturns.NEVER;
- FlowReturns new_breaks = FlowReturns.NEVER;
- bool new_returns_set = false, new_breaks_set = false;
-
- Report.Debug (2, "MERGING CHILDREN", branching, branching.Type,
- this, children.Length);
-
- foreach (UsageVector child in children) {
- Report.Debug (2, " MERGING CHILD", child, child.is_finally);
-
- if (!child.is_finally) {
- if (child.Breaks != FlowReturns.UNREACHABLE) {
- // If Returns is already set, perform an
- // `And' operation on it, otherwise just set just.
- if (!new_returns_set) {
- new_returns = child.Returns;
- new_returns_set = true;
- } else
- new_returns = AndFlowReturns (
- new_returns, child.Returns);
- }
-
- // If Breaks is already set, perform an
- // `And' operation on it, otherwise just set just.
- if (!new_breaks_set) {
- new_breaks = child.Breaks;
- new_breaks_set = true;
- } else
- new_breaks = AndFlowReturns (
- new_breaks, child.Breaks);
- }
-
- // Ignore unreachable children.
- if (child.Returns == FlowReturns.UNREACHABLE)
- continue;
-
- // A local variable is initialized after a flow branching if it
- // has been initialized in all its branches which do neither
- // always return or always throw an exception.
- //
- // If a branch may return, but does not always return, then we
- // can treat it like a never-returning branch here: control will
- // only reach the code position after the branching if we did not
- // return here.
- //
- // It's important to distinguish between always and sometimes
- // returning branches here:
- //
- // 1 int a;
- // 2 if (something) {
- // 3 return;
- // 4 a = 5;
- // 5 }
- // 6 Console.WriteLine (a);
- //
- // The if block in lines 3-4 always returns, so we must not look
- // at the initialization of `a' in line 4 - thus it'll still be
- // uninitialized in line 6.
- //
- // On the other hand, the following is allowed:
- //
- // 1 int a;
- // 2 if (something)
- // 3 a = 5;
- // 4 else
- // 5 return;
- // 6 Console.WriteLine (a);
- //
- // Here, `a' is initialized in line 3 and we must not look at
- // line 5 since it always returns.
- //
- if (child.is_finally) {
- if (new_locals == null)
- new_locals = locals.Clone ();
- new_locals.Or (child.locals);
-
- if (parameters != null) {
- if (new_params == null)
- new_params = parameters.Clone ();
- new_params.Or (child.parameters);
- }
- } else {
- if (!child.AlwaysReturns && !child.AlwaysBreaks) {
- if (new_locals != null)
- new_locals.And (child.locals);
- else {
- new_locals = locals.Clone ();
- new_locals.Or (child.locals);
- }
- } else if (children.Length == 1) {
- new_locals = locals.Clone ();
- new_locals.Or (child.locals);
- }
-
- // An `out' parameter must be assigned in all branches which do
- // not always throw an exception.
- if (parameters != null) {
- bool and_params = child.Breaks != FlowReturns.EXCEPTION;
- if (branching.Type == FlowBranchingType.EXCEPTION)
- and_params &= child.Returns != FlowReturns.NEVER;
- if (and_params) {
- if (new_params != null)
- new_params.And (child.parameters);
- else {
- new_params = parameters.Clone ();
- new_params.Or (child.parameters);
- }
- } else if ((children.Length == 1) || (new_params == null)) {
- new_params = parameters.Clone ();
- new_params.Or (child.parameters);
- }
- }
- }
- }
-
- Returns = new_returns;
- if ((branching.Type == FlowBranchingType.BLOCK) ||
- (branching.Type == FlowBranchingType.EXCEPTION) ||
- (new_breaks == FlowReturns.UNREACHABLE) ||
- (new_breaks == FlowReturns.EXCEPTION))
- Breaks = new_breaks;
- else if (branching.Type == FlowBranchingType.SWITCH_SECTION)
- Breaks = new_returns;
- else if (branching.Type == FlowBranchingType.SWITCH){
- if (new_breaks == FlowReturns.ALWAYS)
- Breaks = FlowReturns.ALWAYS;
- }
-
- //
- // We've now either reached the point after the branching or we will
- // never get there since we always return or always throw an exception.
- //
- // If we can reach the point after the branching, mark all locals and
- // parameters as initialized which have been initialized in all branches
- // we need to look at (see above).
- //
-
- if (((new_breaks != FlowReturns.ALWAYS) &&
- (new_breaks != FlowReturns.EXCEPTION) &&
- (new_breaks != FlowReturns.UNREACHABLE)) ||
- (children.Length == 1)) {
- if (new_locals != null)
- locals.Or (new_locals);
-
- if (new_params != null)
- parameters.Or (new_params);
- }
-
- Report.Debug (2, "MERGING CHILDREN DONE", branching.Type,
- new_params, new_locals, new_returns, new_breaks,
- branching.Infinite, branching.MayLeaveLoop, this);
-
- if (branching.Type == FlowBranchingType.SWITCH_SECTION) {
- if ((new_breaks != FlowReturns.ALWAYS) &&
- (new_breaks != FlowReturns.EXCEPTION) &&
- (new_breaks != FlowReturns.UNREACHABLE))
- Report.Error (163, branching.Location,
- "Control cannot fall through from one " +
- "case label to another");
- }
-
- if (branching.Infinite && !branching.MayLeaveLoop) {
- Report.Debug (1, "INFINITE", new_returns, new_breaks,
- Returns, Breaks, this);
-
- // We're actually infinite.
- if (new_returns == FlowReturns.NEVER) {
- Breaks = FlowReturns.UNREACHABLE;
- return FlowReturns.UNREACHABLE;
- }
-
- // If we're an infinite loop and do not break, the code after
- // the loop can never be reached. However, if we may return
- // from the loop, then we do always return (or stay in the loop
- // forever).
- if ((new_returns == FlowReturns.SOMETIMES) ||
- (new_returns == FlowReturns.ALWAYS)) {
- Returns = FlowReturns.ALWAYS;
- return FlowReturns.ALWAYS;
- }
- }
-
- if (branching.Type == FlowBranchingType.LOOP_BLOCK) {
- Report.Debug (2, "MERGING LOOP BLOCK DONE", branching,
- branching.Infinite, branching.MayLeaveLoop,
- new_breaks, new_returns);
-
- // If we may leave the loop, then we do not always return.
- if (branching.MayLeaveLoop && (new_returns == FlowReturns.ALWAYS)) {
- Returns = FlowReturns.SOMETIMES;
- return FlowReturns.SOMETIMES;
- }
-
- // A `break' in a loop does not "break" in the outer block.
- Breaks = FlowReturns.NEVER;
- }
-
- return new_returns;
- }
-
- // <summary>
- // Tells control flow analysis that the current code position may be reached with
- // a forward jump from any of the origins listed in `origin_vectors' which is a
- // list of UsageVectors.
- //
- // This is used when resolving forward gotos - in the following example, the
- // variable `a' is uninitialized in line 8 becase this line may be reached via
- // the goto in line 4:
- //
- // 1 int a;
- //
- // 3 if (something)
- // 4 goto World;
- //
- // 6 a = 5;
- //
- // 7 World:
- // 8 Console.WriteLine (a);
- //
- // </summary>
- public void MergeJumpOrigins (ICollection origin_vectors)
- {
- Report.Debug (1, "MERGING JUMP ORIGIN", this);
-
- real_breaks = FlowReturns.NEVER;
- real_returns = FlowReturns.NEVER;
-
- foreach (UsageVector vector in origin_vectors) {
- Report.Debug (1, " MERGING JUMP ORIGIN", vector);
-
- locals.And (vector.locals);
- if (parameters != null)
- parameters.And (vector.parameters);
- Breaks = AndFlowReturns (Breaks, vector.Breaks);
- Returns = AndFlowReturns (Returns, vector.Returns);
- }
-
- Report.Debug (1, "MERGING JUMP ORIGIN DONE", this);
- }
-
- // <summary>
- // This is used at the beginning of a finally block if there were
- // any return statements in the try block or one of the catch blocks.
- // </summary>
- public void MergeFinallyOrigins (ICollection finally_vectors)
- {
- Report.Debug (1, "MERGING FINALLY ORIGIN", this);
-
- real_breaks = FlowReturns.NEVER;
-
- foreach (UsageVector vector in finally_vectors) {
- Report.Debug (1, " MERGING FINALLY ORIGIN", vector);
-
- if (parameters != null)
- parameters.And (vector.parameters);
- Breaks = AndFlowReturns (Breaks, vector.Breaks);
- }
-
- is_finally = true;
-
- Report.Debug (1, "MERGING FINALLY ORIGIN DONE", this);
- }
-
- public void CheckOutParameters (FlowBranching branching)
- {
- if (parameters != null)
- branching.CheckOutParameters (parameters, branching.Location);
- }
-
- // <summary>
- // Performs an `or' operation on the locals and the parameters.
- // </summary>
- public void Or (UsageVector new_vector)
- {
- locals.Or (new_vector.locals);
- if (parameters != null)
- parameters.Or (new_vector.parameters);
- }
-
- // <summary>
- // Performs an `and' operation on the locals.
- // </summary>
- public void AndLocals (UsageVector new_vector)
- {
- locals.And (new_vector.locals);
- }
-
- // <summary>
- // Returns a deep copy of the parameters.
- // </summary>
- public MyBitVector Parameters {
- get {
- if (parameters != null)
- return parameters.Clone ();
- else
- return null;
- }
- }
-
- // <summary>
- // Returns a deep copy of the locals.
- // </summary>
- public MyBitVector Locals {
- get {
- return locals.Clone ();
- }
- }
-
- //
- // Debugging stuff.
- //
-
- public override string ToString ()
- {
- StringBuilder sb = new StringBuilder ();
-
- sb.Append ("Vector (");
- sb.Append (id);
- sb.Append (",");
- sb.Append (Returns);
- sb.Append (",");
- sb.Append (Breaks);
- if (parameters != null) {
- sb.Append (" - ");
- sb.Append (parameters);
- }
- sb.Append (" - ");
- sb.Append (locals);
- sb.Append (")");
-
- return sb.ToString ();
- }
- }
-
- FlowBranching (FlowBranchingType type, Location loc)
- {
- this.Block = null;
- this.Location = loc;
- this.Type = type;
- id = ++next_id;
- }
-
- // <summary>
- // Creates a new flow branching for `block'.
- // This is used from Block.Resolve to create the top-level branching of
- // the block.
- // </summary>
- public FlowBranching (Block block, Location loc)
- : this (FlowBranchingType.BLOCK, loc)
- {
- Block = block;
- Parent = null;
-
- param_map = block.ParameterMap;
- local_map = block.LocalMap;
-
- UsageVector vector = new UsageVector (null, param_map.Length, local_map.Length);
-
- AddSibling (vector);
- }
-
- // <summary>
- // Creates a new flow branching which is contained in `parent'.
- // You should only pass non-null for the `block' argument if this block
- // introduces any new variables - in this case, we need to create a new
- // usage vector with a different size than our parent's one.
- // </summary>
- public FlowBranching (FlowBranching parent, FlowBranchingType type,
- Block block, Location loc)
- : this (type, loc)
- {
- Parent = parent;
- Block = block;
-
- UsageVector vector;
- if (Block != null) {
- param_map = Block.ParameterMap;
- local_map = Block.LocalMap;
-
- vector = new UsageVector (parent.CurrentUsageVector, param_map.Length,
- local_map.Length);
- } else {
- param_map = Parent.param_map;
- local_map = Parent.local_map;
- vector = new UsageVector (Parent.CurrentUsageVector);
- }
-
- AddSibling (vector);
-
- switch (Type) {
- case FlowBranchingType.EXCEPTION:
- finally_vectors = new ArrayList ();
- break;
-
- default:
- break;
- }
- }
-
- void AddSibling (UsageVector uv)
- {
- if (Siblings != null) {
- UsageVector[] ns = new UsageVector [Siblings.Length + 1];
- for (int i = 0; i < Siblings.Length; ++i)
- ns [i] = Siblings [i];
- Siblings = ns;
- } else {
- Siblings = new UsageVector [1];
- }
- Siblings [Siblings.Length - 1] = uv;
- }
-
- // <summary>
- // Returns the branching's current usage vector.
- // </summary>
- public UsageVector CurrentUsageVector
- {
- get {
- return Siblings [Siblings.Length - 1];
- }
- }
-
- // <summary>
- // Creates a sibling of the current usage vector.
- // </summary>
- public void CreateSibling ()
- {
- AddSibling (new UsageVector (Parent.CurrentUsageVector));
-
- Report.Debug (1, "CREATED SIBLING", CurrentUsageVector);
- }
-
- // <summary>
- // Creates a sibling for a `finally' block.
- // </summary>
- public void CreateSiblingForFinally ()
- {
- if (Type != FlowBranchingType.EXCEPTION)
- throw new NotSupportedException ();
-
- CreateSibling ();
-
- CurrentUsageVector.MergeFinallyOrigins (finally_vectors);
- }
-
- // <summary>
- // Check whether all `out' parameters have been assigned.
- // </summary>
- public void CheckOutParameters (MyBitVector parameters, Location loc)
- {
- if (InTryBlock ())
- return;
-
- for (int i = 0; i < param_map.Count; i++) {
- VariableInfo var = param_map [i];
-
- if (var == null)
- continue;
-
- if (var.IsAssigned (parameters))
- continue;
-
- Report.Error (177, loc, "The out parameter `" +
- param_map.VariableNames [i] + "' must be " +
- "assigned before control leave the current method.");
- }
- }
-
- // <summary>
- // Merge a child branching.
- // </summary>
- public FlowReturns MergeChild (FlowBranching child)
- {
- FlowReturns returns = CurrentUsageVector.MergeChildren (child, child.Siblings);
-
- if ((child.Type != FlowBranchingType.LOOP_BLOCK) &&
- (child.Type != FlowBranchingType.SWITCH_SECTION))
- MayLeaveLoop |= child.MayLeaveLoop;
-
- return returns;
- }
-
- // <summary>
- // Does the toplevel merging.
- // </summary>
- public FlowReturns MergeTopBlock ()
- {
- if ((Type != FlowBranchingType.BLOCK) || (Block == null))
- throw new NotSupportedException ();
-
- UsageVector vector = new UsageVector (null, param_map.Length, local_map.Length);
-
- Report.Debug (1, "MERGING TOP BLOCK", Location, vector);
-
- vector.MergeChildren (this, Siblings);
-
- if (Siblings.Length == 1)
- Siblings [0] = vector;
- else {
- Siblings = null;
- AddSibling (vector);
- }
-
- Report.Debug (1, "MERGING TOP BLOCK DONE", Location, vector);
-
- if (vector.Breaks != FlowReturns.EXCEPTION) {
- if (!vector.AlwaysBreaks)
- CheckOutParameters (CurrentUsageVector.Parameters, Location);
- return vector.AlwaysBreaks ? FlowReturns.ALWAYS : vector.Returns;
- } else
- return FlowReturns.EXCEPTION;
- }
-
- public bool InTryBlock ()
- {
- if (finally_vectors != null)
- return true;
- else if (Parent != null)
- return Parent.InTryBlock ();
- else
- return false;
- }
-
- public void AddFinallyVector (UsageVector vector)
- {
- if (finally_vectors != null) {
- finally_vectors.Add (vector.Clone ());
- return;
- }
-
- if (Parent != null)
- Parent.AddFinallyVector (vector);
- else
- throw new NotSupportedException ();
- }
-
- public bool IsAssigned (VariableInfo vi)
- {
- return CurrentUsageVector.IsAssigned (vi);
- }
-
- public bool IsFieldAssigned (VariableInfo vi, string field_name)
- {
- if (CurrentUsageVector.IsAssigned (vi))
- return true;
-
- return CurrentUsageVector.IsFieldAssigned (vi, field_name);
- }
-
- public void SetAssigned (VariableInfo vi)
- {
- CurrentUsageVector.SetAssigned (vi);
- }
-
- public void SetFieldAssigned (VariableInfo vi, string name)
- {
- CurrentUsageVector.SetFieldAssigned (vi, name);
- }
-
- public bool IsReachable ()
- {
- bool reachable;
-
- switch (Type) {
- case FlowBranchingType.SWITCH_SECTION:
- // The code following a switch block is reachable unless the switch
- // block always returns.
- reachable = !CurrentUsageVector.AlwaysReturns;
- break;
-
- case FlowBranchingType.LOOP_BLOCK:
- // The code following a loop is reachable unless the loop always
- // returns or it's an infinite loop without any `break's in it.
- reachable = !CurrentUsageVector.AlwaysReturns &&
- (CurrentUsageVector.Breaks != FlowReturns.UNREACHABLE);
- break;
-
- default:
- // The code following a block or exception is reachable unless the
- // block either always returns or always breaks.
- if (MayLeaveLoop)
- reachable = true;
- else
- reachable = !CurrentUsageVector.AlwaysBreaks &&
- !CurrentUsageVector.AlwaysReturns;
- break;
- }
-
- Report.Debug (1, "REACHABLE", this, Type, CurrentUsageVector.Returns,
- CurrentUsageVector.Breaks, CurrentUsageVector, MayLeaveLoop,
- reachable);
-
- return reachable;
- }
-
- public override string ToString ()
- {
- StringBuilder sb = new StringBuilder ("FlowBranching (");
-
- sb.Append (id);
- sb.Append (",");
- sb.Append (Type);
- if (Block != null) {
- sb.Append (" - ");
- sb.Append (Block.ID);
- sb.Append (" - ");
- sb.Append (Block.StartLocation);
- }
- sb.Append (" - ");
- sb.Append (Siblings.Length);
- sb.Append (" - ");
- sb.Append (CurrentUsageVector);
- sb.Append (")");
- return sb.ToString ();
- }
- }
-
- // <summary>
- // This is used by the flow analysis code to keep track of the type of local variables
- // and variables.
- //
- // The flow code uses a BitVector to keep track of whether a variable has been assigned
- // or not. This is easy for fundamental types (int, char etc.) or reference types since
- // you can only assign the whole variable as such.
- //
- // For structs, we also need to keep track of all its fields. To do this, we allocate one
- // bit for the struct itself (it's used if you assign/access the whole struct) followed by
- // one bit for each of its fields.
- //
- // This class computes this `layout' for each type.
- // </summary>
- public class TypeInfo
- {
- public readonly Type Type;
-
- // <summary>
- // Total number of bits a variable of this type consumes in the flow vector.
- // </summary>
- public readonly int TotalLength;
-
- // <summary>
- // Number of bits the simple fields of a variable of this type consume
- // in the flow vector.
- // </summary>
- public readonly int Length;
-
- // <summary>
- // This is only used by sub-structs.
- // </summary>
- public readonly int Offset;
-
- // <summary>
- // If this is a struct.
- // </summary>
- public readonly bool IsStruct;
-
- // <summary>
- // If this is a struct, all fields which are structs theirselves.
- // </summary>
- public TypeInfo[] SubStructInfo;
-
- protected readonly StructInfo struct_info;
- private static Hashtable type_hash = new Hashtable ();
-
- public static TypeInfo GetTypeInfo (Type type)
- {
- TypeInfo info = (TypeInfo) type_hash [type];
- if (info != null)
- return info;
-
- info = new TypeInfo (type);
- type_hash.Add (type, info);
- return info;
- }
-
- public static TypeInfo GetTypeInfo (TypeContainer tc)
- {
- TypeInfo info = (TypeInfo) type_hash [tc.TypeBuilder];
- if (info != null)
- return info;
-
- info = new TypeInfo (tc);
- type_hash.Add (tc.TypeBuilder, info);
- return info;
- }
-
- private TypeInfo (Type type)
- {
- this.Type = type;
-
- struct_info = StructInfo.GetStructInfo (type);
- if (struct_info != null) {
- Length = struct_info.Length;
- TotalLength = struct_info.TotalLength;
- SubStructInfo = struct_info.StructFields;
- IsStruct = true;
- } else {
- Length = 0;
- TotalLength = 1;
- IsStruct = false;
- }
- }
-
- private TypeInfo (TypeContainer tc)
- {
- this.Type = tc.TypeBuilder;
-
- struct_info = StructInfo.GetStructInfo (tc);
- if (struct_info != null) {
- Length = struct_info.Length;
- TotalLength = struct_info.TotalLength;
- SubStructInfo = struct_info.StructFields;
- IsStruct = true;
- } else {
- Length = 0;
- TotalLength = 1;
- IsStruct = false;
- }
- }
-
- protected TypeInfo (StructInfo struct_info, int offset)
- {
- this.struct_info = struct_info;
- this.Offset = offset;
- this.Length = struct_info.Length;
- this.TotalLength = struct_info.TotalLength;
- this.SubStructInfo = struct_info.StructFields;
- this.Type = struct_info.Type;
- this.IsStruct = true;
- }
-
- public int GetFieldIndex (string name)
- {
- if (struct_info == null)
- return 0;
-
- return struct_info [name];
- }
-
- public TypeInfo GetSubStruct (string name)
- {
- if (struct_info == null)
- return null;
-
- return struct_info.GetStructField (name);
- }
-
- // <summary>
- // A struct's constructor must always assign all fields.
- // This method checks whether it actually does so.
- // </summary>
- public bool IsFullyInitialized (FlowBranching branching, VariableInfo vi, Location loc)
- {
- if (struct_info == null)
- return true;
-
- bool ok = true;
- for (int i = 0; i < struct_info.Count; i++) {
- FieldInfo field = struct_info.Fields [i];
-
- if (!branching.IsFieldAssigned (vi, field.Name)) {
- Report.Error (171, loc,
- "Field `" + TypeManager.CSharpName (Type) +
- "." + field.Name + "' must be fully initialized " +
- "before control leaves the constructor");
- ok = false;
- }
- }
-
- return ok;
- }
-
- public override string ToString ()
- {
- return String.Format ("TypeInfo ({0}:{1}:{2}:{3})",
- Type, Offset, Length, TotalLength);
- }
-
- protected class StructInfo {
- public readonly Type Type;
- public readonly FieldInfo[] Fields;
- public readonly TypeInfo[] StructFields;
- public readonly int Count;
- public readonly int CountPublic;
- public readonly int CountNonPublic;
- public readonly int Length;
- public readonly int TotalLength;
- public readonly bool HasStructFields;
-
- private static Hashtable field_type_hash = new Hashtable ();
- private Hashtable struct_field_hash;
- private Hashtable field_hash;
-
- protected bool InTransit = false;
-
- // Private constructor. To save memory usage, we only need to create one instance
- // of this class per struct type.
- private StructInfo (Type type)
- {
- this.Type = type;
-
- field_type_hash.Add (type, this);
-
- if (type is TypeBuilder) {
- TypeContainer tc = TypeManager.LookupTypeContainer (type);
-
- ArrayList fields = tc.Fields;
-
- ArrayList public_fields = new ArrayList ();
- ArrayList non_public_fields = new ArrayList ();
-
- if (fields != null) {
- foreach (Field field in fields) {
- if ((field.ModFlags & Modifiers.STATIC) != 0)
- continue;
- if ((field.ModFlags & Modifiers.PUBLIC) != 0)
- public_fields.Add (field.FieldBuilder);
- else
- non_public_fields.Add (field.FieldBuilder);
- }
- }
-
- CountPublic = public_fields.Count;
- CountNonPublic = non_public_fields.Count;
- Count = CountPublic + CountNonPublic;
-
- Fields = new FieldInfo [Count];
- public_fields.CopyTo (Fields, 0);
- non_public_fields.CopyTo (Fields, CountPublic);
- } else {
- FieldInfo[] public_fields = type.GetFields (
- BindingFlags.Instance|BindingFlags.Public);
- FieldInfo[] non_public_fields = type.GetFields (
- BindingFlags.Instance|BindingFlags.NonPublic);
-
- CountPublic = public_fields.Length;
- CountNonPublic = non_public_fields.Length;
- Count = CountPublic + CountNonPublic;
-
- Fields = new FieldInfo [Count];
- public_fields.CopyTo (Fields, 0);
- non_public_fields.CopyTo (Fields, CountPublic);
- }
-
- struct_field_hash = new Hashtable ();
- field_hash = new Hashtable ();
-
- Length = 0;
- StructFields = new TypeInfo [Count];
- StructInfo[] sinfo = new StructInfo [Count];
-
- InTransit = true;
-
- for (int i = 0; i < Count; i++) {
- FieldInfo field = (FieldInfo) Fields [i];
-
- sinfo [i] = GetStructInfo (field.FieldType);
- if (sinfo [i] == null)
- field_hash.Add (field.Name, ++Length);
- else if (sinfo [i].InTransit) {
- Report.Error (523, String.Format (
- "Struct member '{0}.{1}' of type '{2}' causes " +
- "a cycle in the structure layout",
- type, field.Name, sinfo [i].Type));
- sinfo [i] = null;
- return;
- }
- }
-
- InTransit = false;
-
- TotalLength = Length + 1;
- for (int i = 0; i < Count; i++) {
- FieldInfo field = (FieldInfo) Fields [i];
-
- if (sinfo [i] == null)
- continue;
-
- field_hash.Add (field.Name, TotalLength);
-
- HasStructFields = true;
- StructFields [i] = new TypeInfo (sinfo [i], TotalLength);
- struct_field_hash.Add (field.Name, StructFields [i]);
- TotalLength += sinfo [i].TotalLength;
- }
- }
-
- public int this [string name] {
- get {
- if (field_hash.Contains (name))
- return (int) field_hash [name];
- else
- return 0;
- }
- }
-
- public TypeInfo GetStructField (string name)
- {
- return (TypeInfo) struct_field_hash [name];
- }
-
- public static StructInfo GetStructInfo (Type type)
- {
- if (!TypeManager.IsValueType (type) || TypeManager.IsEnumType (type) ||
- TypeManager.IsBuiltinType (type))
- return null;
-
- StructInfo info = (StructInfo) field_type_hash [type];
- if (info != null)
- return info;
-
- return new StructInfo (type);
- }
-
- public static StructInfo GetStructInfo (TypeContainer tc)
- {
- StructInfo info = (StructInfo) field_type_hash [tc.TypeBuilder];
- if (info != null)
- return info;
-
- return new StructInfo (tc.TypeBuilder);
- }
- }
- }
-
- // <summary>
- // This is used by the flow analysis code to store information about a single local variable
- // or parameter. Depending on the variable's type, we need to allocate one or more elements
- // in the BitVector - if it's a fundamental or reference type, we just need to know whether
- // it has been assigned or not, but for structs, we need this information for each of its fields.
- // </summary>
- public class VariableInfo {
- public readonly string Name;
- public readonly TypeInfo TypeInfo;
-
- // <summary>
- // The bit offset of this variable in the flow vector.
- // </summary>
- public readonly int Offset;
-
- // <summary>
- // The number of bits this variable needs in the flow vector.
- // The first bit always specifies whether the variable as such has been assigned while
- // the remaining bits contain this information for each of a struct's fields.
- // </summary>
- public readonly int Length;
-
- // <summary>
- // If this is a parameter of local variable.
- // </summary>
- public readonly bool IsParameter;
-
- public readonly LocalInfo LocalInfo;
- public readonly int ParameterIndex;
-
- readonly VariableInfo Parent;
- VariableInfo[] sub_info;
-
- protected VariableInfo (string name, Type type, int offset)
- {
- this.Name = name;
- this.Offset = offset;
- this.TypeInfo = TypeInfo.GetTypeInfo (type);
-
- Length = TypeInfo.TotalLength;
-
- Initialize ();
- }
-
- protected VariableInfo (VariableInfo parent, TypeInfo type)
- {
- this.Name = parent.Name;
- this.TypeInfo = type;
- this.Offset = parent.Offset + type.Offset;
- this.Parent = parent;
- this.Length = type.TotalLength;
-
- this.IsParameter = parent.IsParameter;
- this.LocalInfo = parent.LocalInfo;
- this.ParameterIndex = parent.ParameterIndex;
-
- Initialize ();
- }
-
- protected void Initialize ()
- {
- TypeInfo[] sub_fields = TypeInfo.SubStructInfo;
- if (sub_fields != null) {
- sub_info = new VariableInfo [sub_fields.Length];
- for (int i = 0; i < sub_fields.Length; i++) {
- if (sub_fields [i] != null)
- sub_info [i] = new VariableInfo (this, sub_fields [i]);
- }
- } else
- sub_info = new VariableInfo [0];
- }
-
- public VariableInfo (LocalInfo local_info, int offset)
- : this (local_info.Name, local_info.VariableType, offset)
- {
- this.LocalInfo = local_info;
- this.IsParameter = false;
- }
-
- public VariableInfo (string name, Type type, int param_idx, int offset)
- : this (name, type, offset)
- {
- this.ParameterIndex = param_idx;
- this.IsParameter = true;
- }
-
- public bool IsAssigned (EmitContext ec)
- {
- return !ec.DoFlowAnalysis || ec.CurrentBranching.IsAssigned (this);
- }
-
- public bool IsAssigned (EmitContext ec, Location loc)
- {
- if (IsAssigned (ec))
- return true;
-
- Report.Error (165, loc,
- "Use of unassigned local variable `" + Name + "'");
- ec.CurrentBranching.SetAssigned (this);
- return false;
- }
-
- public bool IsAssigned (MyBitVector vector)
- {
- if (vector [Offset])
- return true;
-
- for (VariableInfo parent = Parent; parent != null; parent = parent.Parent)
- if (vector [parent.Offset])
- return true;
-
- // Return unless this is a struct.
- if (!TypeInfo.IsStruct)
- return false;
-
- // Ok, so each field must be assigned.
- for (int i = 0; i < TypeInfo.Length; i++) {
- if (!vector [Offset + i + 1])
- return false;
- }
-
- // Ok, now check all fields which are structs.
- for (int i = 0; i < sub_info.Length; i++) {
- VariableInfo sinfo = sub_info [i];
- if (sinfo == null)
- continue;
-
- if (!sinfo.IsAssigned (vector))
- return false;
- }
-
- vector [Offset] = true;
- return true;
- }
-
- public void SetAssigned (EmitContext ec)
- {
- if (ec.DoFlowAnalysis)
- ec.CurrentBranching.SetAssigned (this);
- }
-
- public void SetAssigned (MyBitVector vector)
- {
- vector [Offset] = true;
- }
-
- public bool IsFieldAssigned (EmitContext ec, string name, Location loc)
- {
- if (!ec.DoFlowAnalysis || ec.CurrentBranching.IsFieldAssigned (this, name))
- return true;
-
- Report.Error (170, loc,
- "Use of possibly unassigned field `" + name + "'");
- ec.CurrentBranching.SetFieldAssigned (this, name);
- return false;
- }
-
- public bool IsFieldAssigned (MyBitVector vector, string field_name)
- {
- int field_idx = TypeInfo.GetFieldIndex (field_name);
-
- if (field_idx == 0)
- return true;
-
- return vector [Offset + field_idx];
- }
-
- public void SetFieldAssigned (EmitContext ec, string name)
- {
- if (ec.DoFlowAnalysis)
- ec.CurrentBranching.SetFieldAssigned (this, name);
- }
-
- public void SetFieldAssigned (MyBitVector vector, string field_name)
- {
- int field_idx = TypeInfo.GetFieldIndex (field_name);
-
- if (field_idx == 0)
- return;
-
- vector [Offset + field_idx] = true;
- }
-
- public VariableInfo GetSubStruct (string name)
- {
- TypeInfo type = TypeInfo.GetSubStruct (name);
-
- if (type == null)
- return null;
-
- return new VariableInfo (this, type);
- }
-
- public override string ToString ()
- {
- return String.Format ("VariableInfo ({0}:{1}:{2}:{3}:{4})",
- Name, TypeInfo, Offset, Length, IsParameter);
- }
- }
-
- // <summary>
- // This is used by the flow code to hold the `layout' of the flow vector for
- // all locals and all parameters (ie. we create one instance of this class for the
- // locals and another one for the params).
- // </summary>
- public class VariableMap {
- // <summary>
- // The number of variables in the map.
- // </summary>
- public readonly int Count;
-
- // <summary>
- // Total length of the flow vector for this map.
- // <summary>
- public readonly int Length;
-
- // <summary>
- // Type and name of all the variables.
- // Note that this is null for variables for which we do not need to compute
- // assignment info.
- // </summary>
- public readonly Type[] VariableTypes;
- public readonly string[] VariableNames;
-
- VariableInfo[] map;
-
- public VariableMap (InternalParameters ip)
- {
- Count = ip != null ? ip.Count : 0;
- map = new VariableInfo [Count];
- VariableNames = new string [Count];
- VariableTypes = new Type [Count];
- Length = 0;
-
- for (int i = 0; i < Count; i++) {
- Parameter.Modifier mod = ip.ParameterModifier (i);
-
- if ((mod & Parameter.Modifier.OUT) == 0)
- continue;
-
- VariableNames [i] = ip.ParameterName (i);
- VariableTypes [i] = TypeManager.GetElementType (ip.ParameterType (i));
-
- map [i] = new VariableInfo (VariableNames [i], VariableTypes [i], i, Length);
- Length += map [i].Length;
- }
- }
-
- public VariableMap (LocalInfo[] locals)
- : this (null, locals)
- { }
-
- public VariableMap (VariableMap parent, LocalInfo[] locals)
- {
- int offset = 0, start = 0;
- if (parent != null) {
- offset = parent.Length;
- start = parent.Count;
- }
-
- Count = locals.Length + start;
- map = new VariableInfo [Count];
- VariableNames = new string [Count];
- VariableTypes = new Type [Count];
- Length = offset;
-
- if (parent != null) {
- parent.map.CopyTo (map, 0);
- parent.VariableNames.CopyTo (VariableNames, 0);
- parent.VariableTypes.CopyTo (VariableTypes, 0);
- }
-
- for (int i = start; i < Count; i++) {
- LocalInfo li = locals [i-start];
-
- if (li.VariableType == null)
- continue;
-
- VariableNames [i] = li.Name;
- VariableTypes [i] = li.VariableType;
-
- map [i] = li.VariableInfo = new VariableInfo (li, Length);
- Length += map [i].Length;
- }
- }
-
- // <summary>
- // Returns the VariableInfo for variable @index or null if we don't need to
- // compute assignment info for this variable.
- // </summary>
- public VariableInfo this [int index] {
- get {
- return map [index];
- }
- }
-
- public override string ToString ()
- {
- return String.Format ("VariableMap ({0}:{1})", Count, Length);
- }
- }
-
public class LocalInfo {
public Expression Type;
[Flags]
public enum Flags : byte {
Implicit = 1,
- Unchecked = 2
+ Unchecked = 2,
+ BlockUsed = 4,
+ VariablesInitialized = 8,
+ HasRet = 16
}
Flags flags;
//
Block switch_block;
- bool used = false;
-
static int id;
int this_id;
variables.Add (name, vi);
- if (variables_initialized)
+ if ((flags & Flags.VariablesInitialized) != 0)
throw new Exception ();
// Console.WriteLine ("Adding {0} to {1}", name, ID);
public void AddStatement (Statement s)
{
statements.Add (s);
- used = true;
+ flags |= Flags.BlockUsed;
}
public bool Used {
get {
- return used;
+ return (flags & Flags.BlockUsed) != 0;
}
}
public void Use ()
{
- used = true;
+ flags |= Flags.BlockUsed;
}
VariableMap param_map, local_map;
- bool variables_initialized = false;
public VariableMap ParameterMap {
get {
- if (!variables_initialized)
+ if ((flags & Flags.VariablesInitialized) == 0)
throw new Exception ();
return param_map;
public VariableMap LocalMap {
get {
- if (!variables_initialized)
+ if ((flags & Flags.VariablesInitialized) == 0)
throw new Exception ();
return local_map;
/// <remarks>
/// tc: is our typecontainer (to resolve type references)
/// ig: is the code generator:
- /// toplevel: the toplevel block. This is used for checking
- /// that no two labels with the same name are used.
/// </remarks>
- public void EmitMeta (EmitContext ec, InternalParameters ip, Block toplevel)
+ public void EmitMeta (EmitContext ec, InternalParameters ip)
{
DeclSpace ds = ec.DeclSpace;
ILGenerator ig = ec.ig;
local_map = new VariableMap (locals);
param_map = new VariableMap (ip);
- variables_initialized = true;
+ flags |= Flags.VariablesInitialized;
bool old_check_state = ec.ConstantCheckState;
ec.ConstantCheckState = (flags & Flags.Unchecked) == 0;
//
if (children != null){
foreach (Block b in children)
- b.EmitMeta (ec, ip, toplevel);
+ b.EmitMeta (ec, ip);
}
}
b.UsageWarning ();
}
- bool has_ret = false;
-
public override bool Resolve (EmitContext ec)
{
Block prev_block = ec.CurrentBlock;
Report.Debug (1, "RESOLVE BLOCK DONE", StartLocation, ec.CurrentBranching);
- FlowReturns returns = ec.EndFlowBranching ();
+ FlowBranching.FlowReturns returns = ec.EndFlowBranching ();
ec.CurrentBlock = prev_block;
// If we're a non-static `struct' constructor which doesn't have an
// initializer, then we must initialize all of the struct's fields.
- if ((this_variable != null) && (returns != FlowReturns.EXCEPTION) &&
+ if ((this_variable != null) && (returns != FlowBranching.FlowReturns.Exception) &&
!this_variable.IsThisAssigned (ec, loc))
ok = false;
"This label has not been referenced");
}
- if ((returns == FlowReturns.ALWAYS) ||
- (returns == FlowReturns.EXCEPTION) ||
- (returns == FlowReturns.UNREACHABLE))
- has_ret = true;
+ if ((returns == FlowBranching.FlowReturns.Always) ||
+ (returns == FlowBranching.FlowReturns.Exception) ||
+ (returns == FlowBranching.FlowReturns.Unreachable))
+ flags |= Flags.HasRet;
return ok;
}
foreach (Statement s in statements)
s.Emit (ec);
- return has_ret;
+ return (flags & Flags.HasRet) != 0;
}
public override bool Emit (EmitContext ec)
ec.Switch = this;
ec.Switch.SwitchType = SwitchType;
- ec.StartFlowBranching (FlowBranchingType.SWITCH, loc);
+ ec.StartFlowBranching (FlowBranching.BranchingType.Switch, loc);
bool first = true;
foreach (SwitchSection ss in Sections){
if (!first)
- ec.CurrentBranching.CreateSibling ();
+ ec.CurrentBranching.CreateSibling (FlowBranching.SiblingType.SwitchSection);
else
first = false;
if (!got_default)
- ec.CurrentBranching.CreateSibling ();
+ ec.CurrentBranching.CreateSibling (FlowBranching.SiblingType.SwitchSection);
ec.EndFlowBranching ();
ec.Switch = old_switch;
{
bool ok = true;
- ec.StartFlowBranching (FlowBranchingType.EXCEPTION, Block.StartLocation);
+ ec.StartFlowBranching (FlowBranching.BranchingType.Exception, Block.StartLocation);
Report.Debug (1, "START OF TRY BLOCK", Block.StartLocation);
Report.Debug (1, "START OF CATCH BLOCKS", vector);
foreach (Catch c in Specific){
- ec.CurrentBranching.CreateSibling ();
+ ec.CurrentBranching.CreateSibling (FlowBranching.SiblingType.Catch);
Report.Debug (1, "STARTED SIBLING FOR CATCH", ec.CurrentBranching);
if (c.Name != null) {
Report.Debug (1, "END OF CATCH BLOCKS", ec.CurrentBranching);
if (General != null){
- ec.CurrentBranching.CreateSibling ();
+ ec.CurrentBranching.CreateSibling (FlowBranching.SiblingType.Catch);
Report.Debug (1, "STARTED SIBLING FOR GENERAL", ec.CurrentBranching);
bool old_in_catch = ec.InCatch;
if (Fini != null) {
if (ok)
- ec.CurrentBranching.CreateSiblingForFinally ();
+ ec.CurrentBranching.CreateSibling (FlowBranching.SiblingType.Finally);
Report.Debug (1, "STARTED SIBLING FOR FINALLY", ec.CurrentBranching, vector);
bool old_in_finally = ec.InFinally;
ec.InFinally = old_in_finally;
}
- FlowReturns returns = ec.EndFlowBranching ();
+ FlowBranching.FlowReturns returns = ec.EndFlowBranching ();
FlowBranching.UsageVector f_vector = ec.CurrentBranching.CurrentUsageVector;
Report.Debug (1, "END OF FINALLY", ec.CurrentBranching, returns, vector, f_vector);
- if ((returns == FlowReturns.SOMETIMES) || (returns == FlowReturns.ALWAYS)) {
+ if ((returns == FlowBranching.FlowReturns.Sometimes) || (returns == FlowBranching.FlowReturns.Always)) {
ec.CurrentBranching.CheckOutParameters (f_vector.Parameters, loc);
}
Report.Debug (1, "END OF TRY", ec.CurrentBranching);
- if (returns != FlowReturns.ALWAYS) {
+ if (returns != FlowBranching.FlowReturns.Always) {
// Unfortunately, System.Reflection.Emit automatically emits a leave
// 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.
/// </summary>
public class Foreach : Statement {
Expression type;
- LocalVariableReference variable;
+ Expression variable;
Expression expr;
Statement statement;
ForeachHelperMethods hm;
empty = new EmptyExpression (hm.element_type);
}
- ec.StartFlowBranching (FlowBranchingType.LOOP_BLOCK, loc);
- ec.CurrentBranching.CreateSibling ();
+ ec.StartFlowBranching (FlowBranching.BranchingType.LoopBlock, loc);
+ ec.CurrentBranching.CreateSibling (FlowBranching.SiblingType.Conditional);
//
//
if (conv == null)
return false;
- if (variable.ResolveLValue (ec, empty) == null)
+ variable = variable.ResolveLValue (ec, empty);
+ if (variable == null)
return false;
if (!statement.Resolve (ec))
return false;
- FlowReturns returns = ec.EndFlowBranching ();
+ FlowBranching.FlowReturns returns = ec.EndFlowBranching ();
return true;
}
bool EmitCollectionForeach (EmitContext ec)
{
ILGenerator ig = ec.ig;
- LocalBuilder enumerator, disposable;
+ VariableStorage enumerator, disposable;
- enumerator = ig.DeclareLocal (hm.enumerator_type);
+ enumerator = new VariableStorage (ec, hm.enumerator_type);
if (hm.is_disposable)
- disposable = ig.DeclareLocal (TypeManager.idisposable_type);
+ disposable = new VariableStorage (ec, TypeManager.idisposable_type);
else
disposable = null;
-
+
+ enumerator.EmitThis ();
//
// Instantiate the enumerator
//
expr.Emit (ec);
ig.Emit (OpCodes.Callvirt, hm.get_enumerator);
}
- ig.Emit (OpCodes.Stloc, enumerator);
+ enumerator.EmitStore ();
//
// Protect the code in a try/finalize block, so that
Label end_try = ig.DefineLabel ();
ig.MarkLabel (ec.LoopBegin);
- ig.Emit (OpCodes.Ldloc, enumerator);
+ enumerator.EmitLoad ();
ig.Emit (OpCodes.Callvirt, hm.move_next);
ig.Emit (OpCodes.Brfalse, end_try);
- ig.Emit (OpCodes.Ldloc, enumerator);
+ if (ec.InIterator)
+ ec.EmitThis ();
+
+ enumerator.EmitLoad ();
ig.Emit (OpCodes.Callvirt, hm.get_current);
- variable.EmitAssign (ec, conv);
+ if (ec.InIterator){
+ conv.Emit (ec);
+ ig.Emit (OpCodes.Stfld, ((FieldExpr) variable).FieldInfo);
+ } else
+ ((IAssignMethod)variable).EmitAssign (ec, conv);
+
statement.Emit (ec);
ig.Emit (OpCodes.Br, ec.LoopBegin);
ig.MarkLabel (end_try);
bool old_in_finally = ec.InFinally;
ec.InFinally = true;
ig.BeginFinallyBlock ();
-
- ig.Emit (OpCodes.Ldloc, enumerator);
+
+ disposable.EmitThis ();
+ enumerator.EmitThis ();
+ enumerator.EmitLoad ();
ig.Emit (OpCodes.Isinst, TypeManager.idisposable_type);
- ig.Emit (OpCodes.Stloc, disposable);
- ig.Emit (OpCodes.Ldloc, disposable);
+ disposable.EmitStore ();
+ disposable.EmitLoad ();
ig.Emit (OpCodes.Brfalse, end_finally);
- ig.Emit (OpCodes.Ldloc, disposable);
+ disposable.EmitThis ();
+ disposable.EmitLoad ();
ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void);
ig.MarkLabel (end_finally);
ec.InFinally = old_in_finally;
int rank = array_type.GetArrayRank ();
ILGenerator ig = ec.ig;
- LocalBuilder copy = ig.DeclareLocal (array_type);
+ VariableStorage copy = new VariableStorage (ec, array_type);
//
// Make our copy of the array
//
+ copy.EmitThis ();
expr.Emit (ec);
- ig.Emit (OpCodes.Stloc, copy);
+ copy.EmitStore ();
if (rank == 1){
- LocalBuilder counter = ig.DeclareLocal (TypeManager.int32_type);
+ VariableStorage counter = new VariableStorage (ec,TypeManager.int32_type);
Label loop, test;
-
+
+ counter.EmitThis ();
ig.Emit (OpCodes.Ldc_I4_0);
- ig.Emit (OpCodes.Stloc, counter);
+ counter.EmitStore ();
test = ig.DefineLabel ();
ig.Emit (OpCodes.Br, test);
loop = ig.DefineLabel ();
ig.MarkLabel (loop);
- ig.Emit (OpCodes.Ldloc, copy);
- ig.Emit (OpCodes.Ldloc, counter);
+ if (ec.InIterator)
+ ec.EmitThis ();
+
+ copy.EmitThis ();
+ copy.EmitLoad ();
+ counter.EmitThis ();
+ counter.EmitLoad ();
//
// Load the value, we load the value using the underlying type,
// then we use the variable.EmitAssign to load using the proper cast.
//
ArrayAccess.EmitLoadOpcode (ig, element_type);
- variable.EmitAssign (ec, conv);
+ if (ec.InIterator){
+ conv.Emit (ec);
+ ig.Emit (OpCodes.Stfld, ((FieldExpr) variable).FieldInfo);
+ } else
+ ((IAssignMethod)variable).EmitAssign (ec, conv);
statement.Emit (ec);
ig.MarkLabel (ec.LoopBegin);
- ig.Emit (OpCodes.Ldloc, counter);
+ counter.EmitThis ();
+ counter.EmitThis ();
+ counter.EmitLoad ();
ig.Emit (OpCodes.Ldc_I4_1);
ig.Emit (OpCodes.Add);
- ig.Emit (OpCodes.Stloc, counter);
+ counter.EmitStore ();
ig.MarkLabel (test);
- ig.Emit (OpCodes.Ldloc, counter);
- ig.Emit (OpCodes.Ldloc, copy);
+ counter.EmitThis ();
+ counter.EmitLoad ();
+ copy.EmitThis ();
+ copy.EmitLoad ();
ig.Emit (OpCodes.Ldlen);
ig.Emit (OpCodes.Conv_I4);
ig.Emit (OpCodes.Blt, loop);
} else {
- LocalBuilder [] dim_len = new LocalBuilder [rank];
- LocalBuilder [] dim_count = new LocalBuilder [rank];
+ VariableStorage [] dim_len = new VariableStorage [rank];
+ VariableStorage [] dim_count = new VariableStorage [rank];
Label [] loop = new Label [rank];
Label [] test = new Label [rank];
int dim;
for (dim = 0; dim < rank; dim++){
- dim_len [dim] = ig.DeclareLocal (TypeManager.int32_type);
- dim_count [dim] = ig.DeclareLocal (TypeManager.int32_type);
+ dim_len [dim] = new VariableStorage (ec, TypeManager.int32_type);
+ dim_count [dim] = new VariableStorage (ec, TypeManager.int32_type);
test [dim] = ig.DefineLabel ();
loop [dim] = ig.DefineLabel ();
}
for (dim = 0; dim < rank; dim++){
- ig.Emit (OpCodes.Ldloc, copy);
+ dim_len [dim].EmitThis ();
+ copy.EmitThis ();
+ copy.EmitLoad ();
IntLiteral.EmitInt (ig, dim);
ig.Emit (OpCodes.Callvirt, TypeManager.int_getlength_int);
- ig.Emit (OpCodes.Stloc, dim_len [dim]);
+ dim_len [dim].EmitStore ();
+
}
for (dim = 0; dim < rank; dim++){
+ dim_count [dim].EmitThis ();
ig.Emit (OpCodes.Ldc_I4_0);
- ig.Emit (OpCodes.Stloc, dim_count [dim]);
+ dim_count [dim].EmitStore ();
ig.Emit (OpCodes.Br, test [dim]);
ig.MarkLabel (loop [dim]);
}
- ig.Emit (OpCodes.Ldloc, copy);
- for (dim = 0; dim < rank; dim++)
- ig.Emit (OpCodes.Ldloc, dim_count [dim]);
+ if (ec.InIterator)
+ ec.EmitThis ();
+ copy.EmitThis ();
+ copy.EmitLoad ();
+ for (dim = 0; dim < rank; dim++){
+ dim_count [dim].EmitThis ();
+ dim_count [dim].EmitLoad ();
+ }
//
// FIXME: Maybe we can cache the computation of `get'?
CallingConventions.HasThis| CallingConventions.Standard,
var_type, args);
ig.Emit (OpCodes.Call, get);
- variable.EmitAssign (ec, conv);
+ if (ec.InIterator){
+ conv.Emit (ec);
+ ig.Emit (OpCodes.Stfld, ((FieldExpr) variable).FieldInfo);
+ } else
+ ((IAssignMethod)variable).EmitAssign (ec, conv);
statement.Emit (ec);
ig.MarkLabel (ec.LoopBegin);
for (dim = rank - 1; dim >= 0; dim--){
- ig.Emit (OpCodes.Ldloc, dim_count [dim]);
+ dim_count [dim].EmitThis ();
+ dim_count [dim].EmitThis ();
+ dim_count [dim].EmitLoad ();
ig.Emit (OpCodes.Ldc_I4_1);
ig.Emit (OpCodes.Add);
- ig.Emit (OpCodes.Stloc, dim_count [dim]);
+ dim_count [dim].EmitStore ();
ig.MarkLabel (test [dim]);
- ig.Emit (OpCodes.Ldloc, dim_count [dim]);
- ig.Emit (OpCodes.Ldloc, dim_len [dim]);
+ dim_count [dim].EmitThis ();
+ dim_count [dim].EmitLoad ();
+ dim_len [dim].EmitThis ();
+ dim_len [dim].EmitLoad ();
ig.Emit (OpCodes.Blt, loop [dim]);
}
}