/// </summary>
public virtual void Emit (EmitContext ec)
{
- ec.Mark (loc, true);
+ ec.Mark (loc);
DoEmit (ec);
}
// This routine must be overrided in derived classes and make copies
// of all the data that might be modified if resolved
//
- protected virtual void CloneTo (CloneContext clonectx, Statement target)
- {
- throw new InternalErrorException ("{0} does not implement Statement.CloneTo", this.GetType ());
- }
+ protected abstract void CloneTo (CloneContext clonectx, Statement target);
public Statement Clone (CloneContext clonectx)
{
return Clone (clonectx);
}
+ public abstract void MutateHoistedGenericType (AnonymousMethodStorey storey);
}
//
{
}
+ public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+ {
+ }
+
protected override void CloneTo (CloneContext clonectx, Statement target)
{
// nothing needed.
loc = l;
}
+ public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+ {
+ expr.MutateHoistedGenericType (storey);
+ TrueStatement.MutateHoistedGenericType (storey);
+ if (FalseStatement != null)
+ FalseStatement.MutateHoistedGenericType (storey);
+ }
+
public override bool Resolve (EmitContext ec)
{
bool ok = true;
public class Do : Statement {
public Expression expr;
public Statement EmbeddedStatement;
- bool infinite;
public Do (Statement statement, Expression bool_expr, Location l)
{
if (expr == null)
ok = false;
else if (expr is Constant){
- bool res = !((Constant) expr).IsDefaultValue;
-
- if (res)
- infinite = true;
+ bool infinite = !((Constant) expr).IsDefaultValue;
+ if (infinite)
+ ec.CurrentBranching.CurrentUsageVector.Goto ();
}
- if (infinite)
- ec.CurrentBranching.CurrentUsageVector.Goto ();
ec.EndFlowBranching ();
ec.LoopEnd = old_end;
}
+ public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+ {
+ expr.MutateHoistedGenericType (storey);
+ EmbeddedStatement.MutateHoistedGenericType (storey);
+ }
+
protected override void CloneTo (CloneContext clonectx, Statement t)
{
Do target = (Do) t;
Statement.Emit (ec);
ig.MarkLabel (ec.LoopBegin);
- ec.Mark (loc, true);
+ ec.Mark (loc);
expr.EmitBranchable (ec, while_loop, true);
target.expr = expr.Clone (clonectx);
target.Statement = Statement.Clone (clonectx);
}
+
+ public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+ {
+ expr.MutateHoistedGenericType (storey);
+ Statement.MutateHoistedGenericType (storey);
+ }
}
public class For : Statement {
return ok;
}
-
+
protected override void DoEmit (EmitContext ec)
{
if (InitStatement != null && InitStatement != EmptyStatement.Value)
ec.LoopEnd = old_end;
}
+ public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+ {
+ if (InitStatement != null)
+ InitStatement.MutateHoistedGenericType (storey);
+ if (Test != null)
+ Test.MutateHoistedGenericType (storey);
+ if (Increment != null)
+ Increment.MutateHoistedGenericType (storey);
+
+ Statement.MutateHoistedGenericType (storey);
+ }
+
protected override void CloneTo (CloneContext clonectx, Statement t)
{
For target = (For) t;
expr.EmitStatement (ec);
}
+ public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+ {
+ expr.MutateHoistedGenericType (storey);
+ }
+
public override string ToString ()
{
return "StatementExpression (" + expr + ")";
return false;
}
- AnonymousContainer am = ec.CurrentAnonymousMethod;
- if ((am != null) && am.IsIterator && ec.InIterator) {
+ if (ec.CurrentBlock.Toplevel.IsIterator) {
Report.Error (1622, loc, "Cannot return a value from iterators. Use the yield return " +
"statement to return a value, or yield break to end the iteration");
}
+ AnonymousExpression am = ec.CurrentAnonymousMethod;
if (am == null && ec.ReturnType == TypeManager.void_type) {
MemberCore mc = ec.ResolveContext as MemberCore;
Report.Error (127, loc, "`{0}': A return keyword must not be followed by any expression when method returns void",
ec.ig.Emit (OpCodes.Ret);
}
+ public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+ {
+ if (Expr != null)
+ Expr.MutateHoistedGenericType (storey);
+ }
+
protected override void CloneTo (CloneContext clonectx, Statement t)
{
Return target = (Return) t;
label.AddReference ();
}
+ protected override void CloneTo (CloneContext clonectx, Statement target)
+ {
+ // Nothing to clone
+ }
+
protected override void DoEmit (EmitContext ec)
{
if (label == null)
Label l = label.LabelTarget (ec);
ec.ig.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, l);
}
+
+ public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+ {
+ }
}
public class LabeledStatement : Statement {
vectors = vector;
}
+ protected override void CloneTo (CloneContext clonectx, Statement target)
+ {
+ // nothing to clone
+ }
+
public override bool Resolve (EmitContext ec)
{
// this flow-branching will be terminated when the surrounding block ends
ec.ig.MarkLabel (label);
}
+ public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+ {
+ }
+
public void AddReference ()
{
referenced = true;
loc = l;
}
+ protected override void CloneTo (CloneContext clonectx, Statement target)
+ {
+ // nothing to clone
+ }
+
public override bool Resolve (EmitContext ec)
{
ec.CurrentBranching.CurrentUsageVector.Goto ();
}
ec.ig.Emit (OpCodes.Br, ec.Switch.DefaultTarget);
}
+
+ public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+ {
+ }
}
/// <summary>
ec.ig.Emit (OpCodes.Br, sl.GetILLabelCode (ec));
}
+ public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+ {
+ expr.MutateHoistedGenericType (storey);
+ }
+
protected override void CloneTo (CloneContext clonectx, Statement t)
{
GotoCase target = (GotoCase) t;
target.expr = expr.Clone (clonectx);
- target.sl = sl.Clone (clonectx);
}
}
public override bool Resolve (EmitContext ec)
{
- ec.CurrentBranching.CurrentUsageVector.Goto ();
-
- if (expr == null)
+ if (expr == null) {
+ ec.CurrentBranching.CurrentUsageVector.Goto ();
return ec.CurrentBranching.CheckRethrow (loc);
+ }
- expr = expr.Resolve (ec);
- if (expr == null)
- return false;
-
- ExprClass eclass = expr.eclass;
+ expr = expr.Resolve (ec, ResolveFlags.Type | ResolveFlags.VariableOrValue);
+ ec.CurrentBranching.CurrentUsageVector.Goto ();
- if (!(eclass == ExprClass.Variable || eclass == ExprClass.PropertyAccess ||
- eclass == ExprClass.Value || eclass == ExprClass.IndexerAccess)) {
- expr.Error_UnexpectedKind (ec.DeclContainer, "value, variable, property or indexer access ", loc);
+ if (expr == null)
return false;
- }
Type t = expr.Type;
}
}
+ public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+ {
+ if (expr != null)
+ expr.MutateHoistedGenericType (storey);
+ }
+
protected override void CloneTo (CloneContext clonectx, Statement t)
{
Throw target = (Throw) t;
{
ec.ig.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, ec.LoopEnd);
}
+
+ public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+ {
+ }
protected override void CloneTo (CloneContext clonectx, Statement t)
{
ec.ig.Emit (unwind_protect ? OpCodes.Leave : OpCodes.Br, ec.LoopBegin);
}
+ public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+ {
+ }
+
protected override void CloneTo (CloneContext clonectx, Statement t)
{
// nothing needed.
}
}
- public abstract class Variable
+ public interface ILocalVariable
{
- public abstract Type Type {
- get;
- }
-
- public abstract bool HasInstance {
- get;
- }
-
- public abstract bool NeedsTemporary {
- get;
- }
-
- public abstract void EmitInstance (EmitContext ec);
-
- public abstract void Emit (EmitContext ec);
-
- public abstract void EmitAssign (EmitContext ec);
-
- public abstract void EmitAddressOf (EmitContext ec);
+ void Emit (EmitContext ec);
+ void EmitAssign (EmitContext ec);
+ void EmitAddressOf (EmitContext ec);
}
public interface IKnownVariable {
//
// The information about a user-perceived local variable
//
- public class LocalInfo : IKnownVariable {
- public Expression Type;
+ public class LocalInfo : IKnownVariable, ILocalVariable {
+ public readonly Expression Type;
public Type VariableType;
public readonly string Name;
public readonly Block Block;
public VariableInfo VariableInfo;
-
- Variable var;
- public Variable Variable {
- get { return var; }
- }
+ public HoistedVariable HoistedVariableReference;
[Flags]
enum Flags : byte {
ReadOnly = 2,
Pinned = 4,
IsThis = 8,
- Captured = 16,
AddressTaken = 32,
CompilerGenerated = 64,
IsConstant = 128
public void ResolveVariable (EmitContext ec)
{
- Block theblock = Block;
- if (theblock.ScopeInfo != null)
- var = theblock.ScopeInfo.GetCapturedVariable (this);
+ if (HoistedVariableReference != null)
+ return;
- if (var == null) {
+ if (builder == null) {
if (Pinned)
//
// This is needed to compile on both .NET 1.x and .NET 2.x
builder = TypeManager.DeclareLocalPinned (ec.ig, VariableType);
else
builder = ec.ig.DeclareLocal (VariableType);
-
- var = new LocalVariable (this, builder);
}
}
- public void EmitSymbolInfo (EmitContext ec, string name)
+ public void Emit (EmitContext ec)
+ {
+ ec.ig.Emit (OpCodes.Ldloc, builder);
+ }
+
+ public void EmitAssign (EmitContext ec)
+ {
+ ec.ig.Emit (OpCodes.Stloc, builder);
+ }
+
+ public void EmitAddressOf (EmitContext ec)
+ {
+ ec.ig.Emit (OpCodes.Ldloca, builder);
+ }
+
+ public void EmitSymbolInfo (EmitContext ec)
{
if (builder != null)
ec.DefineLocalVariable (Name, builder);
public bool Resolve (EmitContext ec)
{
- if (VariableType == null) {
- TypeExpr texpr = Type.ResolveAsContextualType (ec, false);
- if (texpr == null)
- return false;
+ if (VariableType != null)
+ return true;
+
+ TypeExpr texpr = Type.ResolveAsContextualType (ec, false);
+ if (texpr == null)
+ return false;
- VariableType = texpr.Type;
- }
+ VariableType = texpr.Type;
if (TypeManager.IsGenericParameter (VariableType))
return true;
- if (VariableType == TypeManager.void_type) {
- Expression.Error_VoidInvalidInTheContext (Location);
- return false;
- }
-
if (VariableType.IsAbstract && VariableType.IsSealed) {
FieldBase.Error_VariableOfStaticClass (Location, Name, VariableType);
return false;
return true;
}
- public bool IsCaptured {
- get { return (flags & Flags.Captured) != 0; }
- set { flags |= Flags.Captured; }
- }
-
public bool IsConstant {
get { return (flags & Flags.IsConstant) != 0; }
set { flags |= Flags.IsConstant; }
get { return Location; }
}
- protected class LocalVariable : Variable
- {
- public readonly LocalInfo LocalInfo;
- LocalBuilder builder;
-
- public LocalVariable (LocalInfo local, LocalBuilder builder)
- {
- this.LocalInfo = local;
- this.builder = builder;
- }
-
- public override Type Type {
- get { return LocalInfo.VariableType; }
- }
-
- public override bool HasInstance {
- get { return false; }
- }
-
- public override bool NeedsTemporary {
- get { return false; }
- }
-
- public override void EmitInstance (EmitContext ec)
- {
- // Do nothing.
- }
-
- public override void Emit (EmitContext ec)
- {
- ec.ig.Emit (OpCodes.Ldloc, builder);
- }
-
- public override void EmitAssign (EmitContext ec)
- {
- ec.ig.Emit (OpCodes.Stloc, builder);
- }
-
- public override void EmitAddressOf (EmitContext ec)
- {
- ec.ig.Emit (OpCodes.Ldloca, builder);
- }
- }
-
public LocalInfo Clone (CloneContext clonectx)
{
//
public Location EndLocation = Location.Null;
public ExplicitBlock Explicit;
- public ToplevelBlock Toplevel;
+ public ToplevelBlock Toplevel; // TODO: Use Explicit
[Flags]
public enum Flags : byte {
HasRet = 8,
IsDestructor = 16,
Unsafe = 32,
- IsIterator = 64
+ IsIterator = 64,
+ HasStoreyAccess = 128
}
protected Flags flags;
public bool Unchecked {
get { return (flags & Flags.Unchecked) != 0; }
- set { flags |= Flags.Unchecked; }
+ set { flags = value ? flags | Flags.Unchecked : flags & ~Flags.Unchecked; }
}
public bool Unsafe {
//
// Labels. (label, block) pairs.
//
- HybridDictionary labels;
+ protected HybridDictionary labels;
//
// Keeps track of (name, type) pairs
//
IDictionary variables;
+ protected IDictionary range_variables;
//
// Keeps track of constants
//
Block switch_block;
- // TODO: merge with scope_initializers
- ExpressionStatement scope_init;
ArrayList scope_initializers;
ArrayList anonymous_children;
int this_id;
int assignable_slots;
- protected ScopeInfo scope_info;
bool unreachable_shown;
bool unreachable;
if (e is VariableReference || (e is Constant && b.GetLocalInfo (name) != null))
return true;
+ if (this is ToplevelBlock) {
+ Report.SymbolRelatedToPreviousError (kvi.Location, name);
+ e.Error_VariableIsUsedBeforeItIsDeclared (name);
+ return false;
+ }
+
//
// Even though we detected the error when the name is used, we
// treat it as if the variable declaration was in error.
LocalInfo vi = GetLocalInfo (name);
if (vi != null) {
Report.SymbolRelatedToPreviousError (vi.Location, name);
- if (Explicit == vi.Block.Explicit)
- Error_AlreadyDeclared (l, name, null);
- else
+ if (Explicit == vi.Block.Explicit) {
+ if (type == Linq.ImplicitQueryParameter.ImplicitType.Instance && type == vi.Type)
+ Error_AlreadyDeclared (l, name);
+ else
+ Error_AlreadyDeclared (l, name, null);
+ } else {
Error_AlreadyDeclared (l, name, "parent");
+ }
return null;
}
public LocalInfo GetLocalInfo (string name)
{
+ LocalInfo ret;
for (Block b = this; b != null; b = b.Parent) {
if (b.variables != null) {
- LocalInfo ret = b.variables [name] as LocalInfo;
+ ret = (LocalInfo) b.variables [name];
+ if (ret != null)
+ return ret;
+ }
+
+ if (b.range_variables != null) {
+ ret = (LocalInfo) b.range_variables [name];
if (ret != null)
return ret;
}
}
+
return null;
}
public int AssignableSlots {
get {
- if ((flags & Flags.VariablesInitialized) == 0)
- throw new Exception ("Variables have not been initialized yet");
+// TODO: Re-enable
+// if ((flags & Flags.VariablesInitialized) == 0)
+// throw new Exception ("Variables have not been initialized yet");
return assignable_slots;
}
}
- public ScopeInfo ScopeInfo {
- get { return scope_info; }
- }
-
- public ScopeInfo CreateScopeInfo ()
- {
- if (scope_info == null)
- scope_info = ScopeInfo.CreateScope (this);
-
- return scope_info;
- }
-
public ArrayList AnonymousChildren {
get { return anonymous_children; }
}
e = ce.ConvertImplicitly (variable_type);
if (e == null) {
- if (!variable_type.IsValueType && variable_type != TypeManager.string_type && !ce.IsDefaultValue)
+ if (TypeManager.IsReferenceType (variable_type))
Const.Error_ConstantCanBeInitializedWithNullOnly (vi.Location, vi.Name);
else
- ce.Error_ValueCannotBeConverted (null, vi.Location, variable_type, false);
+ ce.Error_ValueCannotBeConverted (ec, vi.Location, variable_type, false);
continue;
}
//
public virtual void EmitMeta (EmitContext ec)
{
- Report.Debug (64, "BLOCK EMIT META", this, Parent, Toplevel, ScopeInfo, ec);
- if (ScopeInfo != null) {
- scope_init = ScopeInfo.GetScopeInitializer (ec);
- Report.Debug (64, "BLOCK EMIT META #1", this, Toplevel, ScopeInfo,
- ec, scope_init);
- }
-
if (variables != null){
foreach (LocalInfo vi in variables.Values)
vi.ResolveVariable (ec);
}
}
- private void CheckPossibleMistakenEmptyStatement (Statement s)
+ static void CheckPossibleMistakenEmptyStatement (Statement s)
{
Statement body;
if (s is EmptyStatement)
continue;
- if (s is Block)
- ((Block) s).unreachable = true;
-
if (!unreachable_shown && !(s is LabeledStatement)) {
Report.Warning (162, 2, s.loc, "Unreachable code detected");
unreachable_shown = true;
}
+
+ Block c_block = s as Block;
+ if (c_block != null)
+ c_block.unreachable = c_block.unreachable_shown = true;
}
//
public override void Emit (EmitContext ec)
{
Block prev_block = ec.CurrentBlock;
-
ec.CurrentBlock = this;
- bool emit_debug_info = SymbolWriter.HasSymbolWriter;
- bool is_lexical_block = (this == Explicit) && (Parent != null) &&
- ((flags & Flags.IsIterator) == 0);
-
- bool omit_debug_info = ec.OmitDebuggingInfo;
-
- if (emit_debug_info) {
- if (is_lexical_block)
- ec.BeginScope ();
- }
-
- if ((scope_init != null) || (scope_initializers != null))
+ if (scope_initializers != null) {
SymbolWriter.OpenCompilerGeneratedBlock (ec.ig);
- if (scope_init != null) {
- ec.OmitDebuggingInfo = true;
- scope_init.EmitStatement (ec);
- ec.OmitDebuggingInfo = omit_debug_info;
- }
- if (scope_initializers != null) {
+ bool omit_debug_info = ec.OmitDebuggingInfo;
ec.OmitDebuggingInfo = true;
foreach (StatementExpression s in scope_initializers)
s.Emit (ec);
ec.OmitDebuggingInfo = omit_debug_info;
- }
- if ((scope_init != null) || (scope_initializers != null))
SymbolWriter.CloseCompilerGeneratedBlock (ec.ig);
+ }
- ec.Mark (StartLocation, true);
+ ec.Mark (StartLocation);
DoEmit (ec);
- if (emit_debug_info) {
+ if (SymbolWriter.HasSymbolWriter)
EmitSymbolInfo (ec);
- if (is_lexical_block)
- ec.EndScope ();
- }
-
ec.CurrentBlock = prev_block;
}
protected virtual void EmitSymbolInfo (EmitContext ec)
{
if (variables != null) {
- foreach (DictionaryEntry de in variables) {
- string name = (string) de.Key;
- LocalInfo vi = (LocalInfo) de.Value;
+ foreach (LocalInfo vi in variables.Values) {
+ vi.EmitSymbolInfo (ec);
+ }
+ }
+ }
+
+ public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+ {
+ MutateVariables (storey);
- vi.EmitSymbolInfo (ec, name);
+ foreach (Statement s in statements)
+ s.MutateHoistedGenericType (storey);
+ }
+
+ void MutateVariables (AnonymousMethodStorey storey)
+ {
+ if (variables != null) {
+ foreach (LocalInfo vi in variables.Values) {
+ vi.VariableType = storey.MutateType (vi.VariableType);
}
}
+
+ if (temporary_variables != null) {
+ foreach (LocalInfo vi in temporary_variables)
+ vi.VariableType = storey.MutateType (vi.VariableType);
+ }
}
public override string ToString ()
}
public class ExplicitBlock : Block {
+ HybridDictionary known_variables;
+ protected AnonymousMethodStorey am_storey;
+
public ExplicitBlock (Block parent, Location start, Location end)
: this (parent, (Flags) 0, start, end)
{
this.Explicit = this;
}
- public bool IsIterator {
- get { return (flags & Flags.IsIterator) != 0; }
- }
-
- HybridDictionary known_variables;
-
// <summary>
// Marks a variable with name @name as being used in this or a child block.
// If a variable name has been used in a child block, it's illegal to
Parent.Explicit.AddKnownVariable (name, info);
}
+ public AnonymousMethodStorey AnonymousMethodStorey {
+ get { return am_storey; }
+ }
+
+ //
+ // Creates anonymous method storey in current block
+ //
+ public AnonymousMethodStorey CreateAnonymousMethodStorey (EmitContext ec)
+ {
+ //
+ // When referencing a variable in iterator storey from children anonymous method
+ //
+ if (Toplevel.am_storey is IteratorStorey) {
+ ec.CurrentAnonymousMethod.AddStoreyReference (Toplevel.am_storey);
+ return Toplevel.am_storey;
+ }
+
+ //
+ // An iterator has only 1 storey block
+ //
+ if (ec.CurrentIterator != null)
+ return ec.CurrentIterator.Storey;
+
+ if (am_storey == null) {
+ MemberBase mc = ec.ResolveContext as MemberBase;
+ GenericMethod gm = mc == null ? null : mc.GenericMethod;
+
+ //
+ // Create anonymous method storey for this block
+ //
+ am_storey = new AnonymousMethodStorey (this, ec.TypeContainer, mc, gm, "AnonStorey");
+ }
+
+ //
+ // Creates a link between this block and the anonymous method
+ //
+ // An anonymous method can reference variables from any outer block, but they are
+ // hoisted in their own ExplicitBlock. When more than one block is referenced we
+ // need to create another link between those variable storeys
+ //
+ ec.CurrentAnonymousMethod.AddStoreyReference (am_storey);
+ return am_storey;
+ }
+
+ public override void Emit (EmitContext ec)
+ {
+ if (am_storey != null)
+ am_storey.EmitHoistedVariables (ec);
+
+ bool emit_debug_info = SymbolWriter.HasSymbolWriter && Parent != null && !(am_storey is IteratorStorey);
+ if (emit_debug_info)
+ ec.BeginScope ();
+
+ base.Emit (ec);
+
+ if (emit_debug_info)
+ ec.EndScope ();
+ }
+
+ public override void EmitMeta (EmitContext ec)
+ {
+ //
+ // Creates anonymous method storey
+ //
+ if (am_storey != null) {
+ if (ec.CurrentAnonymousMethod != null && ec.CurrentAnonymousMethod.Storey != null) {
+ am_storey.ChangeParentStorey (ec.CurrentAnonymousMethod.Storey);
+ }
+
+ am_storey.DefineType ();
+ am_storey.ResolveType ();
+ am_storey.DefineMembers ();
+ am_storey.Parent.PartialContainer.AddCompilerGeneratedClass (am_storey);
+ }
+
+ base.EmitMeta (ec);
+ }
+
internal IKnownVariable GetKnownVariable (string name)
{
return known_variables == null ? null : (IKnownVariable) known_variables [name];
}
+ public void PropagateStoreyReference (AnonymousMethodStorey s)
+ {
+ if (Parent != null && am_storey != s) {
+ if (am_storey != null)
+ am_storey.AddParentStoreyReference (s);
+
+ Parent.Explicit.PropagateStoreyReference (s);
+ }
+ }
+
+ public override bool Resolve (EmitContext ec)
+ {
+ bool ok = base.Resolve (ec);
+
+ //
+ // Discard an anonymous method storey when this block has no hoisted variables
+ //
+ if (am_storey != null && !am_storey.HasHoistedVariables) {
+ am_storey.Undo ();
+ am_storey = null;
+ }
+
+ return ok;
+ }
+
protected override void CloneTo (CloneContext clonectx, Statement t)
{
ExplicitBlock target = (ExplicitBlock) t;
public Parameter Parameter {
get { return Block.Parameters [Index]; }
}
+
+ public Type ParameterType {
+ get { return Block.Parameters.Types [Index]; }
+ }
+
public Location Location {
get { return Parameter.Location; }
}
public class ToplevelBlock : ExplicitBlock {
GenericMethod generic;
FlowBranchingToplevel top_level_branching;
- AnonymousContainer anonymous_container;
- RootScopeInfo root_scope;
Parameters parameters;
ToplevelParameterInfo[] parameter_info;
+ LocalInfo this_variable;
+
+ public HoistedVariable HoistedThisVariable;
//
// The parameters for the block.
get { return parameters; }
}
- public bool CompleteContexts (EmitContext ec)
- {
- Report.Debug (64, "TOPLEVEL COMPLETE CONTEXTS", this, Parent, root_scope);
-
- if (root_scope != null)
- root_scope.LinkScopes ();
-
- if (Parent == null && root_scope != null) {
- Report.Debug (64, "TOPLEVEL COMPLETE CONTEXTS #1", this, root_scope);
-
- if (root_scope.DefineType () == null)
- return false;
- if (!root_scope.ResolveType ())
- return false;
- if (!root_scope.ResolveMembers ())
- return false;
- if (!root_scope.DefineMembers ())
- return false;
- }
-
- return true;
- }
-
public GenericMethod GenericMethod {
get { return generic; }
}
- public ToplevelBlock Container {
- get { return Parent == null ? null : Parent.Toplevel; }
+ public bool HasStoreyAccess {
+ set { flags = value ? flags | Flags.HasStoreyAccess : flags & ~Flags.HasStoreyAccess; }
+ get { return (flags & Flags.HasStoreyAccess) != 0; }
}
- public AnonymousContainer AnonymousContainer {
- get { return anonymous_container; }
- set { anonymous_container = value; }
+ public ToplevelBlock Container {
+ get { return Parent == null ? null : Parent.Toplevel; }
}
public ToplevelBlock (Block parent, Parameters parameters, Location start) :
{
}
- public ToplevelBlock (Flags flags, Parameters parameters, Location start) :
+ ToplevelBlock (Flags flags, Parameters parameters, Location start) :
this (null, flags, parameters, start)
{
}
if (parent != null)
parent.AddAnonymousChild (this);
- if (this.parameters.Count != 0)
+ if (!this.parameters.IsEmpty)
ProcessParameters ();
}
return true;
}
- public RootScopeInfo CreateRootScope (TypeContainer host)
- {
- if (root_scope != null)
- return root_scope;
-
- if (Container == null)
- root_scope = new RootScopeInfo (
- this, host, generic, StartLocation);
-
- if (scope_info != null)
- throw new InternalErrorException ();
-
- scope_info = root_scope;
- return root_scope;
- }
-
public override Expression CreateExpressionTree (EmitContext ec)
{
- return ((Statement) statements [0]).CreateExpressionTree (ec);
- }
-
- public void CreateIteratorHost (RootScopeInfo root)
- {
- Report.Debug (64, "CREATE ITERATOR HOST", this, root, Parent, root_scope);
+ if (statements.Count == 1)
+ return ((Statement) statements [0]).CreateExpressionTree (ec);
- if (Parent != null || root_scope != null)
- throw new InternalErrorException ();
-
- scope_info = root_scope = root;
- }
-
- public RootScopeInfo RootScope {
- get {
- if (root_scope != null)
- return root_scope;
- else if (Container != null)
- return Container.RootScope;
- else
- return null;
- }
- }
-
- public FlowBranchingToplevel TopLevelBranching {
- get { return top_level_branching; }
+ return base.CreateExpressionTree (ec);
}
//
- // This is used if anonymous methods are used inside an iterator
- // (see 2test-22.cs for an example).
- //
- // The AnonymousMethod is created while parsing - at a time when we don't
- // know yet that we're inside an iterator, so it's `Container' is initially
- // null. Later on, when resolving the iterator, we need to move the
- // anonymous method into that iterator.
+ // Reformats this block to be top-level iterator block
//
- public void ReParent (ToplevelBlock new_parent)
+ public IteratorStorey ChangeToIterator (Iterator iterator, ToplevelBlock source)
{
- if ((flags & Flags.VariablesInitialized) != 0)
- throw new InternalErrorException ("block has already been resolved");
+ // Create block with original statements
+ ExplicitBlock iter_block = new ExplicitBlock (this, flags, StartLocation, EndLocation);
+ IsIterator = true;
+
+ // TODO: Change to iter_block.statements = statements;
+ foreach (Statement stmt in source.statements)
+ iter_block.AddStatement (stmt);
+ labels = source.labels;
+
+ AddStatement (new IteratorStatement (iterator, iter_block));
+
+ source.statements = new ArrayList (1);
+ source.AddStatement (new Return (iterator, iterator.Location));
+ source.IsIterator = false;
+
+ IteratorStorey iterator_storey = new IteratorStorey (iterator);
+ source.am_storey = iterator_storey;
+ return iterator_storey;
+ }
- Parent = new_parent;
+ public FlowBranchingToplevel TopLevelBranching {
+ get { return top_level_branching; }
}
//
return null;
}
- LocalInfo this_variable = null;
-
// <summary>
// Returns the "this" instance variable of this block.
// See AddThisVariable() for more information.
return this_variable;
}
+ public bool IsIterator {
+ get { return (flags & Flags.IsIterator) != 0; }
+ set { flags = value ? flags | Flags.IsIterator : flags & ~Flags.IsIterator; }
+ }
+
public bool IsThisAssigned (EmitContext ec)
{
return this_variable == null || this_variable.IsThisAssigned (ec);
int offset = Parent == null ? 0 : Parent.AssignableSlots;
for (int i = 0; i < orig_count; ++i) {
- Parameter.Modifier mod = parameters.ParameterModifier (i);
+ Parameter.Modifier mod = parameters.FixedParameters [i].ModFlags;
if ((mod & Parameter.Modifier.OUT) != Parameter.Modifier.OUT)
continue;
public override void EmitMeta (EmitContext ec)
{
+ parameters.ResolveVariable ();
+
// Avoid declaring an IL variable for this_variable since it is not accessed
// from the generated IL
if (this_variable != null)
Variables.Remove ("this");
base.EmitMeta (ec);
- parameters.ResolveVariable (this);
}
protected override void EmitSymbolInfo (EmitContext ec)
{
- if ((AnonymousContainer != null) && (AnonymousContainer.Scope != null))
- SymbolWriter.DefineScopeVariable (AnonymousContainer.Scope.ID);
+ AnonymousExpression ae = ec.CurrentAnonymousMethod;
+ if ((ae != null) && (ae.Storey != null))
+ SymbolWriter.DefineScopeVariable (ae.Storey.ID);
base.EmitSymbolInfo (ec);
}
- public void MakeIterator (Iterator iterator)
- {
- flags |= Flags.IsIterator;
-
- Block block = new ExplicitBlock (this, flags, StartLocation, EndLocation);
- foreach (Statement stmt in statements)
- block.AddStatement (stmt);
- statements.Clear ();
- statements.Add (new MoveNextStatement (iterator, block));
- }
-
- protected class MoveNextStatement : Statement {
- Iterator iterator;
- Block block;
-
- public MoveNextStatement (Iterator iterator, Block block)
- {
- this.iterator = iterator;
- this.block = block;
- this.loc = iterator.Location;
- }
-
- public override bool Resolve (EmitContext ec)
- {
- ec.StartFlowBranching (iterator);
- bool ok = block.Resolve (ec);
- ec.EndFlowBranching ();
- return ok;
- }
-
- protected override void DoEmit (EmitContext ec)
- {
- iterator.EmitMoveNext (ec, block);
- }
- }
-
- public override string ToString ()
+ public override void Emit (EmitContext ec)
{
- return String.Format ("{0} ({1}:{2}{3}:{4})", GetType (), ID, StartLocation,
- root_scope, anonymous_container != null ?
- anonymous_container.Scope : null);
+ base.Emit (ec);
+ ec.Mark (EndLocation);
}
}
}
}
+ public Location Location {
+ get { return loc; }
+ }
+
public object Converted {
get {
return converted;
return true;
}
- c = c.ImplicitConversionRequired (required_type, loc);
+ c = c.ImplicitConversionRequired (ec, required_type, loc);
if (c == null)
return false;
label = "default";
else if (converted == NullStringCase)
label = "null";
- else if (TypeManager.IsEnumType (switch_type))
- label = TypeManager.CSharpEnumValue (switch_type, converted);
else
label = converted.ToString ();
Label null_target;
Expression new_expr;
bool is_constant;
+ bool has_null_case;
SwitchSection constant_section;
SwitchSection default_section;
+ ExpressionStatement string_dictionary;
+ FieldExpr switch_cache_field;
+ static int unique_counter;
+
#if GMCS_SOURCE
//
// Nullable Types support for GMCS.
TypeManager.int64_type,
TypeManager.uint64_type,
TypeManager.char_type,
- TypeManager.string_type,
- TypeManager.bool_type
+ TypeManager.string_type
};
}
continue;
if (converted != null){
- Report.ExtraInformation (
- loc,
- String.Format ("reason: more than one conversion to an integral type exist for type {0}",
- TypeManager.CSharpName (expr.Type)));
+ Report.ExtraInformation (loc, "(Ambiguous implicit user defined conversion in previous ");
return null;
}
}
object key = sl.Converted;
+ if (key == SwitchLabel.NullStringCase)
+ has_null_case = true;
+
try {
Elements.Add (key, sl);
} catch (ArgumentException) {
/// <param name="ec"></param>
/// <param name="val"></param>
/// <returns></returns>
- void TableSwitchEmit (EmitContext ec, LocalBuilder val)
+ void TableSwitchEmit (EmitContext ec, Expression val)
{
int element_count = Elements.Count;
object [] element_keys = new object [element_count];
Array.Sort (element_keys);
// initialize the block list with one element per key
- ArrayList key_blocks = new ArrayList ();
+ ArrayList key_blocks = new ArrayList (element_count);
foreach (object key in element_keys)
key_blocks.Add (new KeyBlock (System.Convert.ToInt64 (key)));
// okay now we can start...
ILGenerator ig = ec.ig;
Label lbl_end = ig.DefineLabel (); // at the end ;-)
- Label lbl_default = ig.DefineLabel ();
+ Label lbl_default = default_target;
Type type_keys = null;
if (element_keys.Length > 0)
for (int iBlock = key_blocks.Count - 1; iBlock >= 0; --iBlock)
{
KeyBlock kb = ((KeyBlock) key_blocks [iBlock]);
- lbl_default = (iBlock == 0) ? DefaultTarget : ig.DefineLabel ();
+ lbl_default = (iBlock == 0) ? default_target : ig.DefineLabel ();
if (kb.Length <= 2)
{
- foreach (object key in kb.element_keys)
- {
- ig.Emit (OpCodes.Ldloc, val);
- EmitObjectInteger (ig, key);
+ foreach (object key in kb.element_keys) {
SwitchLabel sl = (SwitchLabel) Elements [key];
- ig.Emit (OpCodes.Beq, sl.GetILLabel (ec));
+ if (key is int && (int) key == 0) {
+ val.EmitBranchable (ec, sl.GetILLabel (ec), false);
+ } else {
+ val.Emit (ec);
+ EmitObjectInteger (ig, key);
+ ig.Emit (OpCodes.Beq, sl.GetILLabel (ec));
+ }
}
}
else
// TODO: optimize constant/I4 cases
// check block range (could be > 2^31)
- ig.Emit (OpCodes.Ldloc, val);
+ val.Emit (ec);
EmitObjectInteger (ig, System.Convert.ChangeType (kb.first, type_keys));
ig.Emit (OpCodes.Blt, lbl_default);
- ig.Emit (OpCodes.Ldloc, val);
+ val.Emit (ec);
EmitObjectInteger (ig, System.Convert.ChangeType (kb.last, type_keys));
ig.Emit (OpCodes.Bgt, lbl_default);
// normalize range
- ig.Emit (OpCodes.Ldloc, val);
+ val.Emit (ec);
if (kb.first != 0)
{
EmitObjectInteger (ig, System.Convert.ChangeType (kb.first, type_keys));
else
{
// normalize range
- ig.Emit (OpCodes.Ldloc, val);
+ val.Emit (ec);
int first = (int) kb.first;
if (first > 0)
{
// make sure to mark other labels in the default section
// the last default just goes to the end
- ig.Emit (OpCodes.Br, lbl_default);
+ if (element_keys.Length > 0)
+ ig.Emit (OpCodes.Br, lbl_default);
// now emit the code for the sections
bool found_default = false;
- bool found_null = false;
- foreach (SwitchSection ss in Sections)
- {
- foreach (SwitchLabel sl in ss.Labels)
- if (sl.Converted == SwitchLabel.NullStringCase)
- found_null = true;
- }
- foreach (SwitchSection ss in Sections)
- {
- foreach (SwitchLabel sl in ss.Labels)
- {
- ig.MarkLabel (sl.GetILLabel (ec));
- ig.MarkLabel (sl.GetILLabelCode (ec));
- if (sl.Converted == SwitchLabel.NullStringCase)
+ foreach (SwitchSection ss in Sections) {
+ foreach (SwitchLabel sl in ss.Labels) {
+ if (sl.Converted == SwitchLabel.NullStringCase) {
ig.MarkLabel (null_target);
- else if (sl.Label == null) {
+ } else if (sl.Label == null) {
ig.MarkLabel (lbl_default);
found_default = true;
- if (!found_null)
+ if (!has_null_case)
ig.MarkLabel (null_target);
}
+ ig.MarkLabel (sl.GetILLabel (ec));
+ ig.MarkLabel (sl.GetILLabelCode (ec));
}
ss.Block.Emit (ec);
}
if (!found_default) {
ig.MarkLabel (lbl_default);
- if (HaveUnwrap && !found_null) {
+ if (!has_null_case) {
ig.MarkLabel (null_target);
}
}
ig.MarkLabel (lbl_end);
}
- //
- // This simple emit switch works, but does not take advantage of the
- // `switch' opcode.
- // TODO: remove non-string logic from here
- // TODO: binary search strings?
- //
- void SimpleSwitchEmit (EmitContext ec, LocalBuilder val)
- {
- ILGenerator ig = ec.ig;
- Label end_of_switch = ig.DefineLabel ();
- Label next_test = ig.DefineLabel ();
- bool first_test = true;
- bool pending_goto_end = false;
- bool null_marked = false;
- bool null_found;
- int section_count = Sections.Count;
-
- // TODO: implement switch optimization for string by using Hashtable
- //if (SwitchType == TypeManager.string_type && section_count > 7)
- // Console.WriteLine ("Switch optimization possible " + loc);
-
- ig.Emit (OpCodes.Ldloc, val);
-
- if (Elements.Contains (SwitchLabel.NullStringCase)){
- ig.Emit (OpCodes.Brfalse, null_target);
- } else
- ig.Emit (OpCodes.Brfalse, default_target);
-
- ig.Emit (OpCodes.Ldloc, val);
- ig.Emit (OpCodes.Call, TypeManager.string_isinterned_string);
- ig.Emit (OpCodes.Stloc, val);
-
- for (int section = 0; section < section_count; section++){
- SwitchSection ss = (SwitchSection) Sections [section];
-
- if (ss == default_section)
- continue;
-
- Label sec_begin = ig.DefineLabel ();
-
- ig.Emit (OpCodes.Nop);
-
- if (pending_goto_end)
- ig.Emit (OpCodes.Br, end_of_switch);
-
- int label_count = ss.Labels.Count;
- null_found = false;
- for (int label = 0; label < label_count; label++){
- SwitchLabel sl = (SwitchLabel) ss.Labels [label];
- ig.MarkLabel (sl.GetILLabel (ec));
-
- if (!first_test){
- ig.MarkLabel (next_test);
- next_test = ig.DefineLabel ();
- }
- //
- // If we are the default target
- //
- if (sl.Label != null){
- object lit = sl.Converted;
-
- if (lit == SwitchLabel.NullStringCase){
- null_found = true;
- if (label + 1 == label_count)
- ig.Emit (OpCodes.Br, next_test);
- continue;
- }
-
- ig.Emit (OpCodes.Ldloc, val);
- ig.Emit (OpCodes.Ldstr, (string)lit);
- if (label_count == 1)
- ig.Emit (OpCodes.Bne_Un, next_test);
- else {
- if (label+1 == label_count)
- ig.Emit (OpCodes.Bne_Un, next_test);
- else
- ig.Emit (OpCodes.Beq, sec_begin);
- }
- }
- }
- if (null_found) {
- ig.MarkLabel (null_target);
- null_marked = true;
- }
- ig.MarkLabel (sec_begin);
- foreach (SwitchLabel sl in ss.Labels)
- ig.MarkLabel (sl.GetILLabelCode (ec));
-
- ss.Block.Emit (ec);
- pending_goto_end = !ss.Block.HasRet;
- first_test = false;
- }
- ig.MarkLabel (next_test);
- ig.MarkLabel (default_target);
- if (!null_marked)
- ig.MarkLabel (null_target);
- if (default_section != null)
- default_section.Block.Emit (ec);
- ig.MarkLabel (end_of_switch);
- }
SwitchSection FindSection (SwitchLabel label)
{
return null;
}
+ public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+ {
+ foreach (SwitchSection ss in Sections)
+ ss.Block.MutateHoistedGenericType (storey);
+ }
+
+ public static void Reset ()
+ {
+ unique_counter = 0;
+ }
+
public override bool Resolve (EmitContext ec)
{
Expr = Expr.Resolve (ec);
Report.Debug (1, "END OF SWITCH BLOCK", loc, ec.CurrentBranching);
- if (TypeManager.string_isinterned_string == null) {
- TypeManager.string_isinterned_string = TypeManager.GetPredefinedMethod (TypeManager.string_type,
- "IsInterned", loc, TypeManager.string_type);
+ if (!ok)
+ return false;
+
+ if (SwitchType == TypeManager.string_type && !is_constant) {
+ // TODO: Optimize single case, and single+default case
+ ResolveStringSwitchMap (ec);
}
- return ok;
+ return true;
+ }
+
+ void ResolveStringSwitchMap (EmitContext ec)
+ {
+ FullNamedExpression string_dictionary_type;
+#if GMCS_SOURCE
+ MemberAccess system_collections_generic = new MemberAccess (new MemberAccess (
+ new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Collections", loc), "Generic", loc);
+
+ string_dictionary_type = new MemberAccess (system_collections_generic, "Dictionary",
+ new TypeArguments (loc,
+ new TypeExpression (TypeManager.string_type, loc),
+ new TypeExpression (TypeManager.int32_type, loc)), loc);
+#else
+ MemberAccess system_collections_generic = new MemberAccess (
+ new QualifiedAliasMember (QualifiedAliasMember.GlobalAlias, "System", loc), "Collections", loc);
+
+ string_dictionary_type = new MemberAccess (system_collections_generic, "Hashtable", loc);
+#endif
+ Field field = new Field (ec.TypeContainer, string_dictionary_type,
+ Modifiers.STATIC | Modifiers.PRIVATE | Modifiers.COMPILER_GENERATED,
+ CompilerGeneratedClass.MakeName (null, "f", "switch$map", unique_counter++), null, loc);
+ if (!field.Define ())
+ return;
+ ec.TypeContainer.PartialContainer.AddField (field);
+
+ ArrayList init = new ArrayList ();
+ int counter = 0;
+ Elements.Clear ();
+ string value = null;
+ foreach (SwitchSection section in Sections) {
+ foreach (SwitchLabel sl in section.Labels) {
+ if (sl.Label == null || sl.Converted == SwitchLabel.NullStringCase) {
+ value = null;
+ continue;
+ }
+
+ value = (string) sl.Converted;
+ ArrayList init_args = new ArrayList (2);
+ init_args.Add (new StringLiteral (value, sl.Location));
+ init_args.Add (new IntConstant (counter, loc));
+ init.Add (new CollectionElementInitializer (init_args, loc));
+ }
+
+ if (value == null)
+ continue;
+
+ Elements.Add (counter, section.Labels [0]);
+ ++counter;
+ }
+
+ ArrayList args = new ArrayList (1);
+ args.Add (new Argument (new IntConstant (Sections.Count, loc)));
+ Expression initializer = new NewInitialize (string_dictionary_type, args,
+ new CollectionOrObjectInitializers (init, loc), loc);
+
+ switch_cache_field = new FieldExpr (field.FieldBuilder, loc);
+ string_dictionary = new SimpleAssign (switch_cache_field, initializer.Resolve (ec));
+ }
+
+ void DoEmitStringSwitch (LocalTemporary value, EmitContext ec)
+ {
+ ILGenerator ig = ec.ig;
+ Label l_initialized = ig.DefineLabel ();
+
+ //
+ // Skip initialization when value is null
+ //
+ value.EmitBranchable (ec, null_target, false);
+
+ //
+ // Check if string dictionary is initialized and initialize
+ //
+ switch_cache_field.EmitBranchable (ec, l_initialized, true);
+ string_dictionary.EmitStatement (ec);
+ ig.MarkLabel (l_initialized);
+
+ LocalTemporary string_switch_variable = new LocalTemporary (TypeManager.int32_type);
+
+#if GMCS_SOURCE
+ ArrayList get_value_args = new ArrayList (2);
+ get_value_args.Add (new Argument (value));
+ get_value_args.Add (new Argument (string_switch_variable, Argument.AType.Out));
+ Expression get_item = new Invocation (new MemberAccess (switch_cache_field, "TryGetValue", loc), get_value_args).Resolve (ec);
+ if (get_item == null)
+ return;
+
+ //
+ // A value was not found, go to default case
+ //
+ get_item.EmitBranchable (ec, default_target, false);
+#else
+ ArrayList get_value_args = new ArrayList (1);
+ get_value_args.Add (value);
+
+ Expression get_item = new IndexerAccess (new ElementAccess (switch_cache_field, get_value_args), loc).Resolve (ec);
+ if (get_item == null)
+ return;
+
+ LocalTemporary get_item_object = new LocalTemporary (TypeManager.object_type);
+ get_item_object.EmitAssign (ec, get_item, true, false);
+ ec.ig.Emit (OpCodes.Brfalse, default_target);
+
+ ExpressionStatement get_item_int = (ExpressionStatement) new SimpleAssign (string_switch_variable,
+ new Cast (new TypeExpression (TypeManager.int32_type, loc), get_item_object, loc)).Resolve (ec);
+
+ get_item_int.EmitStatement (ec);
+ get_item_object.Release (ec);
+#endif
+ TableSwitchEmit (ec, string_switch_variable);
+ string_switch_variable.Release (ec);
}
protected override void DoEmit (EmitContext ec)
null_target = ig.DefineLabel ();
// Store variable for comparission purposes
- LocalBuilder value;
+ // TODO: Don't duplicate non-captured VariableReference
+ LocalTemporary value;
if (HaveUnwrap) {
- value = ig.DeclareLocal (SwitchType);
+ value = new LocalTemporary (SwitchType);
#if GMCS_SOURCE
unwrap.EmitCheck (ec);
ig.Emit (OpCodes.Brfalse, null_target);
new_expr.Emit (ec);
- ig.Emit (OpCodes.Stloc, value);
+ value.Store (ec);
#endif
} else if (!is_constant) {
- value = ig.DeclareLocal (SwitchType);
+ value = new LocalTemporary (SwitchType);
new_expr.Emit (ec);
- ig.Emit (OpCodes.Stloc, value);
+ value.Store (ec);
} else
value = null;
if (is_constant) {
if (constant_section != null)
constant_section.Block.Emit (ec);
- } else if (SwitchType == TypeManager.string_type)
- SimpleSwitchEmit (ec, value);
- else
+ } else if (string_dictionary != null) {
+ DoEmitStringSwitch (value, ec);
+ } else {
TableSwitchEmit (ec, value);
+ }
+
+ if (value != null)
+ value.Release (ec);
// Restore context state.
ig.MarkLabel (ec.LoopEnd);
ArrayList resume_points;
int first_resume_pc;
- public void AddResumePoint (ResumableStatement stmt, Location loc, int pc)
+ public void AddResumePoint (ResumableStatement stmt, int pc)
{
if (resume_points == null) {
resume_points = new ArrayList ();
{
ILGenerator ig = ec.ig;
- temp.Store (ec, expr);
+ temp.EmitAssign (ec, expr);
temp.Emit (ec);
ig.Emit (OpCodes.Call, TypeManager.void_monitor_enter_object);
}
temp.Emit (ec);
ec.ig.Emit (OpCodes.Call, TypeManager.void_monitor_exit_object);
}
+
+ public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+ {
+ expr.MutateHoistedGenericType (storey);
+ temp.MutateHoistedGenericType (storey);
+ Statement.MutateHoistedGenericType (storey);
+ }
protected override void CloneTo (CloneContext clonectx, Statement t)
{
Block.Emit (ec);
}
+ public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+ {
+ Block.MutateHoistedGenericType (storey);
+ }
+
protected override void CloneTo (CloneContext clonectx, Statement t)
{
Unchecked target = (Unchecked) t;
Block.Emit (ec);
}
+ public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+ {
+ Block.MutateHoistedGenericType (storey);
+ }
+
protected override void CloneTo (CloneContext clonectx, Statement t)
{
Checked target = (Checked) t;
using (ec.With (EmitContext.Flags.InUnsafe, true))
Block.Emit (ec);
}
+
+ public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+ {
+ Block.MutateHoistedGenericType (storey);
+ }
+
protected override void CloneTo (CloneContext clonectx, Statement t)
{
Unsafe target = (Unsafe) t;
// Store pointer in pinned location
//
converted.Emit (ec);
- vi.Variable.EmitAssign (ec);
+ vi.EmitAssign (ec);
}
public override void EmitExit (EmitContext ec)
{
ec.ig.Emit (OpCodes.Ldc_I4_0);
ec.ig.Emit (OpCodes.Conv_U);
- vi.Variable.EmitAssign (ec);
+ vi.EmitAssign (ec);
}
}
return;
converted.Emit (ec);
- vi.Variable.EmitAssign (ec);
+ vi.EmitAssign (ec);
}
public override void EmitExit (EmitContext ec)
Report.Error (254, loc, "The right hand side of a fixed statement assignment may not be a cast expression");
return false;
}
-
- //
- // Case 1: & object.
- //
- if (e is Unary && ((Unary) e).Oper == Unary.Operator.AddressOf){
- Expression child = ((Unary) e).Expr;
-
- if (child is ParameterReference || child is LocalVariableReference){
- Report.Error (
- 213, loc,
- "No need to use fixed statement for parameters or " +
- "local variable declarations (address is already " +
- "fixed)");
- return false;
- }
-
- ec.InFixedInitializer = true;
- e = e.Resolve (ec);
- ec.InFixedInitializer = false;
- if (e == null)
- return false;
-
- child = ((Unary) e).Expr;
-
- if (!TypeManager.VerifyUnManaged (child.Type, loc))
- return false;
-
- if (!Convert.ImplicitConversionExists (ec, e, expr_type)) {
- e.Error_ValueCannotBeConverted (ec, e.Location, expr_type, false);
- return false;
- }
-
- data [i] = new ExpressionEmitter (e, vi);
- i++;
-
- continue;
- }
ec.InFixedInitializer = true;
e = e.Resolve (ec);
converted = new Conditional (new Binary (Binary.Operator.LogicalOr,
new Binary (Binary.Operator.Equality, e, new NullLiteral (loc)),
new Binary (Binary.Operator.Equality, new MemberAccess (e, "Length"), new IntConstant (0, loc))),
- NullPointer.Null,
+ new NullPointer (loc),
converted);
converted = converted.Resolve (ec);
}
// Case 4: fixed buffer
- FixedBufferPtr fixed_buffer_ptr = e as FixedBufferPtr;
- if (fixed_buffer_ptr != null) {
- data [i++] = new ExpressionEmitter (fixed_buffer_ptr, vi);
+ if (e is FixedBufferPtr) {
+ data [i++] = new ExpressionEmitter (e, vi);
continue;
}
//
- // For other cases, flag a `this is already fixed expression'
+ // Case 1: & object.
//
- if (e is LocalVariableReference || e is ParameterReference ||
- Convert.ImplicitConversionExists (ec, e, vi.VariableType)){
-
- Report.Error (245, loc, "right hand expression is already fixed, no need to use fixed statement ");
- return false;
+ Unary u = e as Unary;
+ if (u != null && u.Oper == Unary.Operator.AddressOf) {
+ IVariableReference vr = u.Expr as IVariableReference;
+ if (vr == null || !vr.IsFixedVariable) {
+ data [i] = new ExpressionEmitter (e, vi);
+ }
}
- Report.Error (245, loc, "Fixed statement only allowed on strings, arrays or address-of expressions");
- return false;
+ if (data [i++] == null)
+ Report.Error (213, vi.Location, "You cannot use the fixed statement to take the address of an already fixed expression");
+
+ e = Convert.ImplicitConversionRequired (ec, e, expr_type, loc);
}
ec.StartFlowBranching (FlowBranching.BranchingType.Conditional, loc);
}
}
+ public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+ {
+ // Fixed statement cannot be used inside anonymous methods or lambdas
+ throw new NotSupportedException ();
+ }
+
protected override void CloneTo (CloneContext clonectx, Statement t)
{
Fixed target = (Fixed) t;
VarBlock.Emit (ec);
if (Name != null) {
- LocalInfo vi = Block.GetLocalInfo (Name);
- if (vi == null)
- throw new Exception ("Variable does not exist in this block");
-
- if (vi.Variable.NeedsTemporary) {
- LocalBuilder e = ig.DeclareLocal (vi.VariableType);
- ig.Emit (OpCodes.Stloc, e);
+ // TODO: Move to resolve
+ LocalVariableReference lvr = new LocalVariableReference (Block, Name, loc);
+ lvr.Resolve (ec);
+
+ Expression source;
+ if (lvr.IsHoisted) {
+ LocalTemporary lt = new LocalTemporary (lvr.Type);
+ lt.Store (ec);
+ source = lt;
+ } else {
+ // Variable is at the top of the stack
+ source = EmptyExpression.Null;
+ }
- vi.Variable.EmitInstance (ec);
- ig.Emit (OpCodes.Ldloc, e);
- vi.Variable.EmitAssign (ec);
- } else
- vi.Variable.EmitAssign (ec);
+ lvr.EmitAssign (ec, source, false, false);
} else
ig.Emit (OpCodes.Pop);
}
}
+ public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+ {
+ if (type != null)
+ type = storey.MutateType (type);
+ if (VarBlock != null)
+ VarBlock.MutateHoistedGenericType (storey);
+ Block.MutateHoistedGenericType (storey);
+ }
+
protected override void CloneTo (CloneContext clonectx, Statement t)
{
Catch target = (Catch) t;
fini.Emit (ec);
}
+ public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+ {
+ stmt.MutateHoistedGenericType (storey);
+ fini.MutateHoistedGenericType (storey);
+ }
+
protected override void CloneTo (CloneContext clonectx, Statement t)
{
TryFinally target = (TryFinally) t;
ig.EndExceptionBlock ();
}
+ public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+ {
+ Block.MutateHoistedGenericType (storey);
+
+ if (General != null)
+ General.MutateHoistedGenericType (storey);
+ if (Specific != null) {
+ foreach (Catch c in Specific)
+ c.MutateHoistedGenericType (storey);
+ }
+ }
+
protected override void CloneTo (CloneContext clonectx, Statement t)
{
TryCatch target = (TryCatch) t;
protected override void EmitPreTryBody (EmitContext ec)
{
- local_copy.Store (ec, expr);
+ local_copy.EmitAssign (ec, expr);
}
protected override void EmitTryBody (EmitContext ec)
Statement.Emit (ec);
}
- protected override void EmitFinallyBody (EmitContext ec)
+ protected override void EmitFinallyBody (EmitContext ec)
{
ILGenerator ig = ec.ig;
if (!expr_type.IsValueType) {
ig.Emit (OpCodes.Call, mi);
}
+ public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+ {
+ expr_type = storey.MutateType (expr_type);
+ local_copy.MutateHoistedGenericType (storey);
+ Statement.MutateHoistedGenericType (storey);
+ }
+
protected override void CloneTo (CloneContext clonectx, Statement t)
{
UsingTemporary target = (UsingTemporary) t;
}
}
+ public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+ {
+ assign.MutateHoistedGenericType (storey);
+ var.MutateHoistedGenericType (storey);
+ stmt.MutateHoistedGenericType (storey);
+ }
+
public override bool Resolve (EmitContext ec)
{
if (!ResolveVariable (ec))
Expression variable;
Expression expr;
Statement statement;
- ArrayForeach array;
- CollectionForeach collection;
public Foreach (Expression type, LocalVariableReference var, Expression expr,
Statement stmt, Location l)
return false;
}
- //
- // We need an instance variable. Not sure this is the best
- // way of doing this.
- //
- // FIXME: When we implement propertyaccess, will those turn
- // out to return values in ExprClass? I think they should.
- //
- if (!(expr.eclass == ExprClass.Variable || expr.eclass == ExprClass.Value ||
- expr.eclass == ExprClass.PropertyAccess || expr.eclass == ExprClass.IndexerAccess)){
- collection.Error_Enumerator ();
- return false;
- }
-
if (expr.Type.IsArray) {
- array = new ArrayForeach (type, variable, expr, statement, loc);
- return array.Resolve (ec);
+ statement = new ArrayForeach (type, variable, expr, statement, loc);
+ } else {
+ statement = new CollectionForeach (type, variable, expr, statement, loc);
}
- collection = new CollectionForeach (type, variable, expr, statement, loc);
- return collection.Resolve (ec);
+ return statement.Resolve (ec);
}
protected override void DoEmit (EmitContext ec)
ec.LoopBegin = ig.DefineLabel ();
ec.LoopEnd = ig.DefineLabel ();
- if (collection != null)
- collection.Emit (ec);
- else
- array.Emit (ec);
+ statement.Emit (ec);
ec.LoopBegin = old_begin;
ec.LoopEnd = old_end;
protected class ArrayCounter : TemporaryVariable
{
+ StatementExpression increment;
+
public ArrayCounter (Location loc)
: base (TypeManager.int32_type, loc)
- { }
+ {
+ }
- public void Initialize (EmitContext ec)
+ public void ResolveIncrement (EmitContext ec)
{
- EmitThis (ec);
- ec.ig.Emit (OpCodes.Ldc_I4_0);
- EmitStore (ec);
+ increment = new StatementExpression (new UnaryMutator (UnaryMutator.Mode.PostIncrement, this, loc));
+ increment.Resolve (ec);
}
- public void Increment (EmitContext ec)
+ public void EmitIncrement (EmitContext ec)
{
- EmitThis (ec);
- Emit (ec);
- ec.ig.Emit (OpCodes.Ldc_I4_1);
- ec.ig.Emit (OpCodes.Add);
- EmitStore (ec);
+ increment.Emit (ec);
}
}
TemporaryVariable copy;
Expression access;
+ Expression[] length_exprs;
public ArrayForeach (Expression var_type, Expression var,
Expression expr, Statement stmt, Location l)
loc = l;
}
+ protected override void CloneTo (CloneContext clonectx, Statement target)
+ {
+ throw new NotImplementedException ();
+ }
+
public override bool Resolve (EmitContext ec)
{
array_type = expr.Type;
counter = new ArrayCounter [rank];
lengths = new TemporaryVariable [rank];
+ length_exprs = new Expression [rank];
- ArrayList list = new ArrayList ();
+ ArrayList list = new ArrayList (rank);
for (int i = 0; i < rank; i++) {
counter [i] = new ArrayCounter (loc);
- counter [i].Resolve (ec);
+ counter [i].ResolveIncrement (ec);
lengths [i] = new TemporaryVariable (TypeManager.int32_type, loc);
lengths [i].Resolve (ec);
+ if (rank == 1) {
+ length_exprs [i] = new MemberAccess (copy, "Length").Resolve (ec);
+ } else {
+ ArrayList args = new ArrayList (1);
+ args.Add (new Argument (new IntConstant (i, loc)));
+ length_exprs [i] = new Invocation (new MemberAccess (copy, "GetLength"), args).Resolve (ec);
+ }
+
list.Add (counter [i]);
}
{
ILGenerator ig = ec.ig;
- copy.Store (ec, expr);
+ copy.EmitAssign (ec, expr);
Label[] test = new Label [rank];
Label[] loop = new Label [rank];
test [i] = ig.DefineLabel ();
loop [i] = ig.DefineLabel ();
- lengths [i].EmitThis (ec);
- ((ArrayAccess) access).EmitGetLength (ec, i);
- lengths [i].EmitStore (ec);
+ lengths [i].EmitAssign (ec, length_exprs [i]);
}
+ IntConstant zero = new IntConstant (0, loc);
for (int i = 0; i < rank; i++) {
- counter [i].Initialize (ec);
+ counter [i].EmitAssign (ec, zero);
ig.Emit (OpCodes.Br, test [i]);
ig.MarkLabel (loop [i]);
ig.MarkLabel (ec.LoopBegin);
for (int i = rank - 1; i >= 0; i--){
- counter [i].Increment (ec);
+ counter [i].EmitIncrement (ec);
ig.MarkLabel (test [i]);
counter [i].Emit (ec);
ig.MarkLabel (ec.LoopEnd);
}
+
+ public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+ {
+ copy.MutateHoistedGenericType (storey);
+ conv.MutateHoistedGenericType (storey);
+ variable.MutateHoistedGenericType (storey);
+ statement.MutateHoistedGenericType (storey);
+
+ for (int i = 0; i < rank; i++) {
+ counter [i].MutateHoistedGenericType (storey);
+ lengths [i].MutateHoistedGenericType (storey);
+ }
+ }
}
protected class CollectionForeach : Statement
loc = l;
}
+ protected override void CloneTo (CloneContext clonectx, Statement target)
+ {
+ throw new NotImplementedException ();
+ }
+
bool GetEnumeratorFilter (EmitContext ec, MethodInfo mi)
{
Type return_type = mi.ReturnType;
return null;
}
- public void Error_Enumerator ()
+ void Error_Enumerator ()
{
if (enumerator_found) {
return;
this.parent = parent;
}
+ protected override void CloneTo (CloneContext clonectx, Statement target)
+ {
+ throw new NotSupportedException ();
+ }
+
public override bool Resolve (EmitContext ec)
{
return parent.ResolveLoop (ec);
parent.EmitLoopInit (ec);
parent.EmitLoopBody (ec);
}
+
+ public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+ {
+ throw new NotSupportedException ();
+ }
}
class DisposableWrapper : ExceptionStatement {
this.parent = parent;
}
+ protected override void CloneTo (CloneContext clonectx, Statement target)
+ {
+ throw new NotSupportedException ();
+ }
+
public override bool Resolve (EmitContext ec)
{
bool ok = true;
{
parent.EmitFinallyBody (ec);
}
+
+ public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+ {
+ throw new NotSupportedException ();
+ }
}
bool ResolveLoop (EmitContext ec)
void EmitLoopInit (EmitContext ec)
{
- enumerator.Store (ec, init);
+ enumerator.EmitAssign (ec, init);
}
void EmitLoopBody (EmitContext ec)
if (enumerator_type.IsValueType) {
MethodInfo mi = FetchMethodDispose (enumerator_type);
if (mi != null) {
- enumerator.EmitLoadAddress (ec);
+ enumerator.AddressOf (ec, AddressOp.Load);
ig.Emit (OpCodes.Call, mi);
} else {
enumerator.Emit (ec);
ig.Emit (OpCodes.Callvirt, TypeManager.void_dispose_void);
}
}
+
+ public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+ {
+ enumerator_type = storey.MutateType (enumerator_type);
+ init.MutateHoistedGenericType (storey);
+ loop.MutateHoistedGenericType (storey);
+ }
}
protected class CollectionForeachStatement : Statement
this.loc = loc;
}
+ protected override void CloneTo (CloneContext clonectx, Statement target)
+ {
+ throw new NotImplementedException ();
+ }
+
public override bool Resolve (EmitContext ec)
{
current = current.Resolve (ec);
assign.EmitStatement (ec);
statement.Emit (ec);
}
+
+ public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+ {
+ assign.MutateHoistedGenericType (storey);
+ statement.MutateHoistedGenericType (storey);
+ }
}
protected override void CloneTo (CloneContext clonectx, Statement t)
target.expr = expr.Clone (clonectx);
target.statement = statement.Clone (clonectx);
}
+
+ public override void MutateHoistedGenericType (AnonymousMethodStorey storey)
+ {
+ statement.MutateHoistedGenericType (storey);
+ }
}
}