if (sf.IsHiddenLocation (loc))
return false;
-#if NET_4_0
methodSymbols.MarkSequencePoint (ig.ILOffset, sf.SourceFileEntry, loc.Row, loc.Column, false);
-#endif
return true;
}
if ((flags & Options.OmitDebugInfo) != 0)
return;
-#if NET_4_0
methodSymbols.StartBlock (CodeBlockEntry.Type.Lexical, ig.ILOffset);
-#endif
}
public void BeginCompilerScope ()
if ((flags & Options.OmitDebugInfo) != 0)
return;
-#if NET_4_0
methodSymbols.StartBlock (CodeBlockEntry.Type.CompilerGenerated, ig.ILOffset);
-#endif
}
public void EndExceptionBlock ()
if ((flags & Options.OmitDebugInfo) != 0)
return;
-#if NET_4_0
methodSymbols.EndBlock (ig.ILOffset);
-#endif
}
public void CloseConditionalAccess (TypeSpec type)
switch (type.BuiltinType) {
case BuiltinTypeSpec.Type.Bool:
//
- // Workaround MSIL limitation. Load bool element as single bit,
- // bool array can actually store any byte value
+ // bool array can actually store any byte value in underlying byte slot
+ // and C# spec does not specify any normalization rule, except the result
+ // is undefined
//
- ig.Emit (OpCodes.Ldelem_U1);
- ig.Emit (OpCodes.Ldc_I4_0);
- ig.Emit (OpCodes.Cgt_Un);
- break;
case BuiltinTypeSpec.Type.Byte:
ig.Emit (OpCodes.Ldelem_U1);
break;
ig.Emit (OpCodes.Ldind_U1);
break;
case BuiltinTypeSpec.Type.SByte:
- ig.Emit (OpCodes.Ldind_I1);
- break;
case BuiltinTypeSpec.Type.Bool:
ig.Emit (OpCodes.Ldind_I1);
- ig.Emit (OpCodes.Ldc_I4_0);
- ig.Emit (OpCodes.Cgt_Un);
break;
case BuiltinTypeSpec.Type.ULong:
case BuiltinTypeSpec.Type.Long:
ig.Emit (OpCodes.Stobj, type.GetMetaInfo ());
break;
+ case MemberKind.PointerType:
+ ig.Emit (OpCodes.Stind_I);
+ break;
default:
ig.Emit (OpCodes.Stind_Ref);
break;
var ie = new InstanceEmitter (instance_copy, IsAddressCall (instance_copy, call_op, method.DeclaringType));
if (Arguments == null) {
- ie.EmitLoad (ec);
+ ie.EmitLoad (ec, true);
}
} else if (!InstanceExpressionOnStack) {
var ie = new InstanceEmitter (InstanceExpression, IsAddressCall (InstanceExpression, call_op, method.DeclaringType));
instance_address = instance as LocalTemporary;
if (instance_address == null) {
- EmitLoad (ec);
+ EmitLoad (ec, false);
ec.Emit (OpCodes.Dup);
ec.EmitLoadFromPtr (instance.Type);
} else {
instance.Emit (ec);
}
-
- if (instance.Type.Kind == MemberKind.TypeParameter)
- ec.Emit (OpCodes.Box, instance.Type);
} else {
- EmitLoad (ec);
+ EmitLoad (ec, !conditionalAccess);
if (conditionalAccess) {
conditional_access_dup = !IsInexpensiveLoad ();
}
if (conditionalAccess) {
+ if (instance.Type.Kind == MemberKind.TypeParameter)
+ ec.Emit (OpCodes.Box, instance.Type);
+
ec.Emit (OpCodes.Brtrue_S, NullOperatorLabel);
if (conditional_access_dup)
}
}
- public void EmitLoad (EmitContext ec)
+ public void EmitLoad (EmitContext ec, bool boxInstance)
{
var instance_type = instance.Type;
instance.Emit (ec);
// Only to make verifier happy
- if (RequiresBoxing ())
+ if (boxInstance && RequiresBoxing ()) {
ec.Emit (OpCodes.Box, instance_type);
+ }
}
public TypeSpec GetStackType (EmitContext ec)
return false;
}
+ //
+ // Returns true for cheap race-free load, where we can avoid using dup
+ //
bool IsInexpensiveLoad ()
{
if (instance is Constant)
return false;
var vr = instance as VariableReference;
- if (vr != null)
- return !vr.IsRef;
+ if (vr != null) {
+ // Load from captured local would be racy without dup
+ return !vr.IsRef && !vr.IsHoisted;
+ }
if (instance is LocalTemporary)
return true;