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));
+ "`{0}' is not a reference type as required by the lock statement",
+ expr.Type.GetSignatureForError ());
return false;
}
ok &= base.Resolve (ec);
- temp = TemporaryVariableReference.Create (expr.Type, ec.CurrentBlock.Parent, loc);
- temp.Resolve (ec);
+ //
+ // 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 (expr.Type, ec.CurrentBlock.Parent, loc);
+ expr_copy.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);
+ //
+ // 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;
}
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);
}
protected override void EmitTryBody (EmitContext ec)
{
+ //
+ // Monitor.Enter (expr_copy, ref lock_taken)
+ //
+ expr_copy.Emit (ec);
+
+ if (lock_taken != null) {
+ 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 = TypeManager.CoreLookupType (rc.Compiler, "System.Threading", "Monitor", MemberKind.Class, true);
+
+ 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)
return ts;
}
- static MemberSpec GetPredefinedMember (TypeSpec t, MemberFilter filter, Location loc)
+ static MemberSpec GetPredefinedMember (TypeSpec t, MemberFilter filter, bool optional, Location loc)
{
var member = MemberCache.FindMember (t, filter, BindingRestriction.DeclaredOnly);
if (member != null && member.IsAccessible (InternalType.FakeInternalType))
return member;
+ if (optional)
+ return member;
+
string method_args = null;
if (filter.Parameters != null)
method_args = filter.Parameters.GetSignatureForError ();
public static MethodSpec GetPredefinedConstructor (TypeSpec t, Location loc, params TypeSpec [] args)
{
var pc = ParametersCompiled.CreateFullyResolved (args);
- return GetPredefinedMember (t, MemberFilter.Constructor (pc), loc) as MethodSpec;
+ return GetPredefinedMember (t, MemberFilter.Constructor (pc), false, loc) as MethodSpec;
}
//
public static MethodSpec GetPredefinedMethod (TypeSpec t, string name, Location loc, params TypeSpec [] args)
{
var pc = ParametersCompiled.CreateFullyResolved (args);
- return GetPredefinedMethod (t, MemberFilter.Method (name, 0, pc, null), loc);
+ return GetPredefinedMethod (t, MemberFilter.Method (name, 0, pc, null), false, loc);
}
public static MethodSpec GetPredefinedMethod (TypeSpec t, MemberFilter filter, Location loc)
{
- return GetPredefinedMember (t, filter, loc) as MethodSpec;
+ return GetPredefinedMethod (t, filter, false, loc);
+ }
+
+ public static MethodSpec GetPredefinedMethod (TypeSpec t, MemberFilter filter, bool optional, Location loc)
+ {
+ return GetPredefinedMember (t, filter, optional, loc) as MethodSpec;
}
public static FieldSpec GetPredefinedField (TypeSpec t, string name, Location loc, TypeSpec type)
{
- return GetPredefinedMember (t, MemberFilter.Field (name, type), loc) as FieldSpec;
+ return GetPredefinedMember (t, MemberFilter.Field (name, type), false, loc) as FieldSpec;
}
public static PropertySpec GetPredefinedProperty (TypeSpec t, string name, Location loc, TypeSpec type)
{
- return GetPredefinedMember (t, MemberFilter.Property (name, type), loc) as PropertySpec;
+ return GetPredefinedMember (t, MemberFilter.Property (name, type), false, loc) as PropertySpec;
}
public static IList<PredefinedTypeSpec> InitCoreTypes ()