//
using System;
-using System.Text;
-using System.Reflection;
-using System.Reflection.Emit;
-using System.Diagnostics;
using System.Collections.Generic;
+#if STATIC
+using IKVM.Reflection.Emit;
+#else
+using System.Reflection.Emit;
+#endif
+
namespace Mono.CSharp {
public abstract class Statement {
this.initializer = initializer;
}
+ public Declarator (Declarator clone, Expression initializer)
+ {
+ this.li = clone.li;
+ this.initializer = initializer;
+ }
+
#region Properties
public LocalVariable Variable {
if (declarators != null) {
t.declarators = null;
foreach (var d in declarators)
- t.AddDeclarator (new Declarator (d.Variable, d.Initializer == null ? null : d.Initializer.Clone (clonectx)));
+ t.AddDeclarator (new Declarator (d, d.Initializer == null ? null : d.Initializer.Clone (clonectx)));
}
}
}
FixedVariable = 1 << 6,
UsingVariable = 1 << 7,
// DefinitelyAssigned = 1 << 8,
+ IsLocked = 1 << 9,
ReadonlyMask = ForeachVariable | FixedVariable | UsingVariable
}
#region Properties
+ public bool AddressTaken {
+ get { return (flags & Flags.AddressTaken) != 0; }
+ set { flags |= Flags.AddressTaken; }
+ }
+
public Block Block {
get {
return block;
}
}
+ public bool IsLocked {
+ get {
+ return (flags & Flags.IsLocked) != 0;
+ }
+ set {
+ flags = value ? flags | Flags.IsLocked : flags & ~Flags.IsLocked;
+ }
+ }
+
public bool IsThis {
get {
return (flags & Flags.IsThis) != 0;
ec.Emit (OpCodes.Ldloca, builder);
}
+ public string GetReadOnlyContext ()
+ {
+ switch (flags & Flags.ReadonlyMask) {
+ case Flags.FixedVariable:
+ return "fixed variable";
+ case Flags.ForeachVariable:
+ return "foreach iteration variable";
+ case Flags.UsingVariable:
+ return "using variable";
+ }
+
+ throw new InternalErrorException ("Variable is not readonly");
+ }
+
public bool IsThisAssigned (BlockContext ec, Block block)
{
if (VariableInfo == null)
flags |= Flags.Used;
}
- public bool AddressTaken {
- get { return (flags & Flags.AddressTaken) != 0; }
- set { flags |= Flags.AddressTaken; }
- }
-
public override string ToString ()
{
return string.Format ("LocalInfo ({0},{1},{2},{3})", name, type, VariableInfo, Location);
}
-
- public string GetReadOnlyContext ()
- {
- switch (flags & Flags.ReadonlyMask) {
- case Flags.FixedVariable:
- return "fixed variable";
- case Flags.ForeachVariable:
- return "foreach iteration variable";
- case Flags.UsingVariable:
- return "using variable";
- }
-
- throw new InternalErrorException ("Variable is not readonly");
- }
}
/// <summary>
{
if (am_storey != null) {
DefineAnonymousStorey (ec);
- am_storey.EmitStoreyInstantiation (ec);
+ am_storey.EmitStoreyInstantiation (ec, this);
}
bool emit_debug_info = SymbolWriter.HasSymbolWriter && Parent != null && !(am_storey is IteratorStorey);
readonly ParametersBlock block;
readonly int index;
public VariableInfo VariableInfo;
+ bool is_locked;
public ParameterInfo (ParametersBlock block, int index)
{
}
}
+ public bool IsLocked {
+ get {
+ return is_locked;
+ }
+ set {
+ is_locked = value;
+ }
+ }
+
public Location Location {
get {
return Parameter.Location;
var label = value as LabeledStatement;
Block b = block;
if (label != null) {
- if (label.Block == b)
+ if (label.Block == b.Original)
return label;
// TODO: Temporary workaround for the switch block implicit label block
- if (label.Block.IsCompilerGenerated && label.Block.Parent == b)
+ if (label.Block.IsCompilerGenerated && label.Block.Parent == b.Original)
return label;
} else {
List<LabeledStatement> list = (List<LabeledStatement>) value;
for (int i = 0; i < list.Count; ++i) {
label = list[i];
- if (label.Block == b)
+ if (label.Block == b.Original)
return label;
// TODO: Temporary workaround for the switch block implicit label block
- if (label.Block.IsCompilerGenerated && label.Block.Parent == b)
+ if (label.Block.IsCompilerGenerated && label.Block.Parent == b.Original)
return label;
}
}
public SwitchLabel Clone (CloneContext clonectx)
{
+ if (label == null)
+ return this;
+
return new SwitchLabel (label.Clone (clonectx), loc);
}
}
{
var cloned_labels = new List<SwitchLabel> ();
- foreach (SwitchLabel sl in cloned_labels)
+ foreach (SwitchLabel sl in Labels)
cloned_labels.Add (sl.Clone (clonectx));
return new SwitchSection (cloned_labels, clonectx.LookupBlock (Block));
public class Lock : ExceptionStatement {
Expression expr;
- TemporaryVariableReference temp;
+ TemporaryVariableReference expr_copy;
+ TemporaryVariableReference lock_taken;
public Lock (Expression expr, Statement stmt, Location loc)
: base (stmt, loc)
if (!TypeManager.IsReferenceType (expr.Type)){
ec.Report.Error (185, loc,
- "`{0}' is not a reference type as required by the lock statement",
- TypeManager.CSharpName (expr.Type));
- return false;
+ "`{0}' is not a reference type as required by the lock statement",
+ expr.Type.GetSignatureForError ());
+ }
+
+ if (expr.Type.IsGenericParameter) {
+ expr = Convert.ImplicitTypeParameterConversion (expr, TypeManager.object_type);
+ }
+
+ VariableReference lv = expr as VariableReference;
+ bool locked;
+ if (lv != null) {
+ locked = lv.IsLockedByStatement;
+ lv.IsLockedByStatement = true;
+ } else {
+ lv = null;
+ locked = false;
}
ec.StartFlowBranching (this);
- bool ok = Statement.Resolve (ec);
+ Statement.Resolve (ec);
ec.EndFlowBranching ();
- ok &= base.Resolve (ec);
+ if (lv != null) {
+ lv.IsLockedByStatement = locked;
+ }
- temp = TemporaryVariableReference.Create (expr.Type, ec.CurrentBlock.Parent, loc);
- temp.Resolve (ec);
+ base.Resolve (ec);
- if (TypeManager.void_monitor_enter_object == null || TypeManager.void_monitor_exit_object == null) {
- TypeSpec monitor_type = TypeManager.CoreLookupType (ec.Compiler, "System.Threading", "Monitor", MemberKind.Class, true);
- TypeManager.void_monitor_enter_object = TypeManager.GetPredefinedMethod (
- monitor_type, "Enter", loc, TypeManager.object_type);
- TypeManager.void_monitor_exit_object = TypeManager.GetPredefinedMethod (
- monitor_type, "Exit", loc, TypeManager.object_type);
+ //
+ // Have to keep original lock value around to unlock same location
+ // in the case the original has changed or is null
+ //
+ expr_copy = TemporaryVariableReference.Create (TypeManager.object_type, ec.CurrentBlock.Parent, loc);
+ expr_copy.Resolve (ec);
+
+ //
+ // Ensure Monitor methods are available
+ //
+ if (ResolvePredefinedMethods (ec) > 1) {
+ lock_taken = TemporaryVariableReference.Create (TypeManager.bool_type, ec.CurrentBlock.Parent, loc);
+ lock_taken.Resolve (ec);
}
-
- return ok;
+
+ return true;
}
protected override void EmitPreTryBody (EmitContext ec)
{
- temp.EmitAssign (ec, expr);
- temp.Emit (ec);
- ec.Emit (OpCodes.Call, TypeManager.void_monitor_enter_object);
+ expr_copy.EmitAssign (ec, expr);
+
+ if (lock_taken != null) {
+ //
+ // Initialize ref variable
+ //
+ lock_taken.EmitAssign (ec, new BoolLiteral (false, loc));
+ } else {
+ //
+ // Monitor.Enter (expr_copy)
+ //
+ expr_copy.Emit (ec);
+ ec.Emit (OpCodes.Call, TypeManager.void_monitor_enter_object);
+ }
}
protected override void EmitTryBody (EmitContext ec)
{
+ //
+ // Monitor.Enter (expr_copy, ref lock_taken)
+ //
+ if (lock_taken != null) {
+ expr_copy.Emit (ec);
+ lock_taken.LocalInfo.CreateBuilder (ec);
+ lock_taken.AddressOf (ec, AddressOp.Load);
+ ec.Emit (OpCodes.Call, TypeManager.void_monitor_enter_object);
+ }
+
Statement.Emit (ec);
}
protected override void EmitFinallyBody (EmitContext ec)
{
- temp.Emit (ec);
+ //
+ // if (lock_taken) Monitor.Exit (expr_copy)
+ //
+ Label skip = ec.DefineLabel ();
+
+ if (lock_taken != null) {
+ lock_taken.Emit (ec);
+ ec.Emit (OpCodes.Brfalse_S, skip);
+ }
+
+ expr_copy.Emit (ec);
ec.Emit (OpCodes.Call, TypeManager.void_monitor_exit_object);
+ ec.MarkLabel (skip);
+ }
+
+ int ResolvePredefinedMethods (ResolveContext rc)
+ {
+ if (TypeManager.void_monitor_enter_object == null || TypeManager.void_monitor_exit_object == null) {
+ TypeSpec monitor_type = rc.Module.PredefinedTypes.Monitor.Resolve (loc);
+
+ if (monitor_type == null)
+ return 0;
+
+ // Try 4.0 Monitor.Enter (object, ref bool) overload first
+ var filter = MemberFilter.Method ("Enter", 0, new ParametersImported (
+ new[] {
+ new ParameterData (null, Parameter.Modifier.NONE),
+ new ParameterData (null, Parameter.Modifier.REF)
+ },
+ new[] {
+ TypeManager.object_type,
+ TypeManager.bool_type
+ }, false), null);
+
+ TypeManager.void_monitor_enter_object = TypeManager.GetPredefinedMethod (monitor_type, filter, true, loc);
+ if (TypeManager.void_monitor_enter_object == null) {
+ TypeManager.void_monitor_enter_object = TypeManager.GetPredefinedMethod (
+ monitor_type, "Enter", loc, TypeManager.object_type);
+ }
+
+ TypeManager.void_monitor_exit_object = TypeManager.GetPredefinedMethod (
+ monitor_type, "Exit", loc, TypeManager.object_type);
+ }
+
+ return TypeManager.void_monitor_enter_object.Parameters.Count;
}
protected override void CloneTo (CloneContext clonectx, Statement t)
pinned_string.Type = TypeManager.string_type;
if (TypeManager.int_get_offset_to_string_data == null) {
- TypeManager.int_get_offset_to_string_data = TypeManager.GetPredefinedProperty (
- TypeManager.runtime_helpers_type, "OffsetToStringData", pinned_string.Location, TypeManager.int32_type);
+ var helper = rc.Module.PredefinedTypes.RuntimeHelpers.Resolve (loc);
+ if (helper != null) {
+ TypeManager.int_get_offset_to_string_data = TypeManager.GetPredefinedProperty (helper,
+ "OffsetToStringData", pinned_string.Location, TypeManager.int32_type);
+ }
}
eclass = ExprClass.Variable;
}
if (General != null) {
- if (CodeGen.Assembly.WrapNonExceptionThrows) {
- foreach (Catch c in Specific){
- if (c.CatchType == TypeManager.exception_type && PredefinedAttributes.Get.RuntimeCompatibility.IsDefined) {
- ec.Report.Warning (1058, 1, c.loc, "A previous catch clause already catches all exceptions. All non-exceptions thrown will be wrapped in a `System.Runtime.CompilerServices.RuntimeWrappedException'");
- }
- }
+ foreach (Catch c in Specific) {
+ if (c.CatchType != TypeManager.exception_type)
+ continue;
+
+ if (!ec.Module.DeclaringAssembly.WrapNonExceptionThrows)
+ continue;
+
+ if (!ec.Module.PredefinedAttributes.RuntimeCompatibility.IsDefined)
+ continue;
+
+ ec.Report.Warning (1058, 1, c.loc,
+ "A previous catch clause already catches all exceptions. All non-exceptions thrown will be wrapped in a `System.Runtime.CompilerServices.RuntimeWrappedException'");
}
ec.CurrentBranching.CreateSibling (General.Block, FlowBranching.SiblingType.Catch);
return base.Resolve (bc);
}
- public void ResolveExpression (BlockContext bc)
+ public Expression ResolveExpression (BlockContext bc)
{
var e = Initializer.Resolve (bc);
if (e == null)
- return;
+ return null;
li = LocalVariable.CreateCompilerGenerated (e.Type, bc.CurrentBlock, loc);
Initializer = ResolveInitializer (bc, Variable, e);
+ return e;
}
protected override Expression ResolveInitializer (BlockContext bc, LocalVariable li, Expression initializer)
{
- Assign assign;
if (li.Type == InternalType.Dynamic) {
initializer = initializer.Resolve (bc);
if (initializer == null)
return null;
- initializer = Convert.ImplicitConversionRequired (bc, initializer, TypeManager.idisposable_type, loc);
+ // Once there is dynamic used defer conversion to runtime even if we know it will never succeed
+ Arguments args = new Arguments (1);
+ args.Add (new Argument (initializer));
+ initializer = new DynamicConversion (TypeManager.idisposable_type, 0, args, initializer.Location).Resolve (bc);
if (initializer == null)
return null;
var var = LocalVariable.CreateCompilerGenerated (TypeManager.idisposable_type, bc.CurrentBlock, loc);
- assign = new SimpleAssign (var.CreateReferenceExpression (bc, loc), initializer, loc);
- assign.ResolveStatement (bc);
-
dispose_call = CreateDisposeCall (bc, var);
dispose_call.Resolve (bc);
- return assign;
+ return base.ResolveInitializer (bc, li, new SimpleAssign (var.CreateReferenceExpression (bc, loc), initializer, loc));
}
if (li == Variable) {
public override bool Resolve (BlockContext ec)
{
+ VariableReference vr;
+ bool vr_locked = false;
+
using (ec.Set (ResolveContext.Options.UsingInitializerScope)) {
if (decl.Variable == null) {
- decl.ResolveExpression (ec);
+ vr = decl.ResolveExpression (ec) as VariableReference;
+ if (vr != null) {
+ vr_locked = vr.IsLockedByStatement;
+ vr.IsLockedByStatement = true;
+ }
} else {
if (!decl.Resolve (ec))
return false;
if (decl.Declarators != null) {
stmt = decl.RewriteForDeclarators (ec, stmt);
}
+
+ vr = null;
}
}
ec.StartFlowBranching (this);
- bool ok = stmt.Resolve (ec);
+ stmt.Resolve (ec);
ec.EndFlowBranching ();
- ok &= base.Resolve (ec);
+ if (vr != null)
+ vr.IsLockedByStatement = vr_locked;
- return ok;
+ base.Resolve (ec);
+
+ return true;
}
protected override void CloneTo (CloneContext clonectx, Statement t)
ec.StartFlowBranching (FlowBranching.BranchingType.Loop, loc);
ec.CurrentBranching.CreateSibling ();
- // TODO: dynamic
variable.local_info.Type = conv.Type;
variable.Resolve (ec);
// Option 2: Try to match using IEnumerable interfaces with preference of generic version
//
TypeSpec iface_candidate = null;
- for (TypeSpec t = expr.Type; t != null && t != TypeManager.object_type; t = t.BaseType) {
+ var t = expr.Type;
+ do {
var ifaces = t.Interfaces;
if (ifaces != null) {
foreach (var iface in ifaces) {
}
}
}
- }
+
+ if (t.IsGenericParameter)
+ t = t.BaseType;
+ else
+ t = null;
+
+ } while (t != null);
if (iface_candidate == null) {
rc.Report.Error (1579, loc,
public override bool Resolve (BlockContext ec)
{
bool is_dynamic = expr.Type == InternalType.Dynamic;
+
if (is_dynamic) {
expr = Convert.ImplicitConversionRequired (ec, expr, TypeManager.ienumerable_type, loc);
} else if (TypeManager.IsNullableType (expr.Type)) {
- expr = Nullable.Unwrap.Create (expr);
+ expr = new Nullable.UnwrapCall (expr).Resolve (ec);
}
var get_enumerator_mg = ResolveGetEnumerator (ec);