diff --git a/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs b/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs
index d638c33a5..8993c9bc0 100644
--- a/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs
+++ b/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs
@@ -1093,6 +1093,15 @@ namespace ICSharpCode.Decompiler.CSharp
.WithRR(new ResolveResult(trueBranch.Type));
}
+ protected internal override TranslatedExpression VisitAddressOf(AddressOf inst)
+ {
+ // HACK: this is only correct if the argument is an R-value; otherwise we're missing the copy to the temporary
+ var value = Translate(inst.Value);
+ return new DirectionExpression(FieldDirection.Ref, value)
+ .WithILInstruction(inst)
+ .WithRR(new ByReferenceResolveResult(value.ResolveResult, false));
+ }
+
protected internal override TranslatedExpression VisitInvalidInstruction(InvalidInstruction inst)
{
string message = "Invalid IL";
diff --git a/ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs b/ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs
index f4692d8fb..8fb52417f 100644
--- a/ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs
+++ b/ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs
@@ -152,8 +152,8 @@ namespace ICSharpCode.Decompiler.IL
ILInstruction loadInst;
if (FindLoadInNext(next, v, inlinedExpression, out loadInst) == true) {
if (loadInst.OpCode == OpCode.LdLoca) {
- //if (!IsGeneratedValueTypeTemporary((ILInstruction)next, loadInst, v, inlinedExpression))
- return false;
+ if (!IsGeneratedValueTypeTemporary(next, loadInst.Parent, loadInst.ChildIndex, v))
+ return false;
} else {
Debug.Assert(loadInst.OpCode == OpCode.LdLoc);
if (!aggressive && v.Kind != VariableKind.StackSlot && !NonAggressiveInlineInto(next, loadInst, inlinedExpression))
@@ -174,7 +174,7 @@ namespace ICSharpCode.Decompiler.IL
}
return false;
}
- /*
+
///
/// Is this a temporary variable generated by the C# compiler for instance method calls on value type values
///
@@ -182,89 +182,25 @@ namespace ICSharpCode.Decompiler.IL
/// The direct parent of the load within 'next'
/// Index of the load within 'parent'
/// The variable being inlined.
- /// The expression being inlined
- bool IsGeneratedValueTypeTemporary(ILInstruction next, ILInstruction parent, int pos, ILVariable v, ILInstruction inlinedExpression)
+ static bool IsGeneratedValueTypeTemporary(ILInstruction next, ILInstruction parent, int pos, ILVariable v)
{
- if (pos == 0 && v.Type != null && v.Type.IsValueType) {
- // Inlining a value type variable is allowed only if the resulting code will maintain the semantics
- // that the method is operating on a copy.
- // Thus, we have to disallow inlining of other locals, fields, array elements, dereferenced pointers
- switch (inlinedExpression.Code) {
- case ILCode.Ldloc:
- case ILCode.Stloc:
- case ILCode.CompoundAssignment:
- case ILCode.Ldelem_Any:
- case ILCode.Ldelem_I:
- case ILCode.Ldelem_I1:
- case ILCode.Ldelem_I2:
- case ILCode.Ldelem_I4:
- case ILCode.Ldelem_I8:
- case ILCode.Ldelem_R4:
- case ILCode.Ldelem_R8:
- case ILCode.Ldelem_Ref:
- case ILCode.Ldelem_U1:
- case ILCode.Ldelem_U2:
- case ILCode.Ldelem_U4:
- case ILCode.Ldobj:
- case ILCode.Ldind_Ref:
- return false;
- case ILCode.Ldfld:
- case ILCode.Stfld:
- case ILCode.Ldsfld:
- case ILCode.Stsfld:
- // allow inlining field access only if it's a readonly field
- FieldDefinition f = ((FieldReference)inlinedExpression.Operand).Resolve();
- if (!(f != null && f.IsInitOnly))
- return false;
- break;
- case ILCode.Call:
- case ILCode.CallGetter:
- // inlining runs both before and after IntroducePropertyAccessInstructions,
- // so we have to handle both 'call' and 'callgetter'
- MethodReference mr = (MethodReference)inlinedExpression.Operand;
- // ensure that it's not an multi-dimensional array getter
- if (mr.DeclaringType is ArrayType)
- return false;
- goto case ILCode.Callvirt;
- case ILCode.Callvirt:
- case ILCode.CallvirtGetter:
- // don't inline foreach loop variables:
- mr = (MethodReference)inlinedExpression.Operand;
- if (mr.Name == "get_Current" && mr.HasThis)
- return false;
- break;
- case ILCode.Castclass:
- case ILCode.Unbox_Any:
- // These are valid, but might occur as part of a foreach loop variable.
- ILInstruction arg = inlinedExpression.Arguments[0];
- if (arg.Code == ILCode.CallGetter || arg.Code == ILCode.CallvirtGetter || arg.Code == ILCode.Call || arg.Code == ILCode.Callvirt) {
- mr = (MethodReference)arg.Operand;
- if (mr.Name == "get_Current" && mr.HasThis)
- return false; // looks like a foreach loop variable, so don't inline it
- }
- break;
- }
-
+ if (pos == 0 && v.Type != null && v.Type.IsReferenceType == false) {
// inline the compiler-generated variable that are used when accessing a member on a value type:
- switch (parent.Code) {
- case ILCode.Call:
- case ILCode.CallGetter:
- case ILCode.CallSetter:
- case ILCode.Callvirt:
- case ILCode.CallvirtGetter:
- case ILCode.CallvirtSetter:
- MethodReference mr = (MethodReference)parent.Operand;
- return mr.HasThis;
- case ILCode.Stfld:
- case ILCode.Ldfld:
- case ILCode.Ldflda:
- case ILCode.Await:
+ switch (parent.OpCode) {
+ case OpCode.Call:
+ return !((Call)parent).Method.IsStatic;
+ case OpCode.CallVirt:
+ return !((CallVirt)parent).Method.IsStatic;
+ case OpCode.StFld:
+ case OpCode.LdFld:
+ case OpCode.LdFlda:
+ // TODO : Reimplement Await
+ //case OpCode.Await:
return true;
}
}
return false;
}
- */
///
/// Determines whether a variable should be inlined in non-aggressive mode, even though it is not a generated variable.
@@ -354,78 +290,5 @@ namespace ICSharpCode.Decompiler.IL
}
return SemanticHelper.MayReorder(expressionBeingMoved.Flags, expr.Flags);
}
- /*
- ///
- /// Runs a very simple form of copy propagation.
- /// Copy propagation is used in two cases:
- /// 1) assignments from arguments to local variables
- /// If the target variable is assigned to only once (so always is that argument) and the argument is never changed (no ldarga/starg),
- /// then we can replace the variable with the argument.
- /// 2) assignments of address-loading instructions to local variables
- ///
- public void CopyPropagation()
- {
- foreach (ILBlock block in method.GetSelfAndChildrenRecursive()) {
- for (int i = 0; i < block.Body.Count; i++) {
- ILVariable v;
- ILInstruction copiedExpr;
- if (block.Body[i].Match(ILCode.Stloc, out v, out copiedExpr)
- && !v.IsParameter && numStloc.GetOrDefault(v) == 1 && numLdloca.GetOrDefault(v) == 0
- && CanPerformCopyPropagation(copiedExpr, v))
- {
- // un-inline the arguments of the ldArg instruction
- ILVariable[] uninlinedArgs = new ILVariable[copiedExpr.Arguments.Count];
- for (int j = 0; j < uninlinedArgs.Length; j++) {
- uninlinedArgs[j] = new ILVariable { IsGenerated = true, Name = v.Name + "_cp_" + j };
- block.Body.Insert(i++, new ILInstruction(ILCode.Stloc, uninlinedArgs[j], copiedExpr.Arguments[j]));
- }
-
- // perform copy propagation:
- foreach (var expr in method.GetSelfAndChildrenRecursive()) {
- if (expr.Code == ILCode.Ldloc && expr.Operand == v) {
- expr.Code = copiedExpr.Code;
- expr.Operand = copiedExpr.Operand;
- for (int j = 0; j < uninlinedArgs.Length; j++) {
- expr.Arguments.Add(new ILInstruction(ILCode.Ldloc, uninlinedArgs[j]));
- }
- }
- }
-
- block.Body.RemoveAt(i);
- if (uninlinedArgs.Length > 0) {
- // if we un-inlined stuff; we need to update the usage counters
- AnalyzeMethod();
- }
- InlineInto(block.Body, i, aggressive: false); // maybe inlining gets possible after the removal of block.Body[i]
- i -= uninlinedArgs.Length + 1;
- }
- }
- }
- }
-
- bool CanPerformCopyPropagation(ILInstruction expr, ILVariable copyVariable)
- {
- switch (expr.Code) {
- case ILCode.Ldloca:
- case ILCode.Ldelema:
- case ILCode.Ldflda:
- case ILCode.Ldsflda:
- // All address-loading instructions always return the same value for a given operand/argument combination,
- // so they can be safely copied.
- return true;
- case ILCode.Ldloc:
- ILVariable v = (ILVariable)expr.Operand;
- if (v.IsParameter) {
- // Parameters can be copied only if they aren't assigned to (directly or indirectly via ldarga)
- return numLdloca.GetOrDefault(v) == 0 && numStloc.GetOrDefault(v) == 0;
- } else {
- // Variables are be copied only if both they and the target copy variable are generated,
- // and if the variable has only a single assignment
- return v.IsGenerated && copyVariable.IsGenerated && numLdloca.GetOrDefault(v) == 0 && numStloc.GetOrDefault(v) == 1;
- }
- default:
- return false;
- }
- }*/
}
}