Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions src/DelegateDecompiler/OptimizeExpressionVisitor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,12 @@ protected override Expression VisitBinary(BinaryExpression node)
{
var left = Visit(node.Left);
var right = Visit(node.Right);

if (TryOptimizeTypeAsComparison(node.NodeType, left, right, out var typeIsExpression))
{
return typeIsExpression;
}

if (node.Right is ConstantExpression rightConstant)
{
if (rightConstant.Value as bool? == false)
Expand Down Expand Up @@ -537,6 +543,32 @@ protected override Expression VisitParameter(ParameterExpression node)
}
}

static bool TryOptimizeTypeAsComparison(ExpressionType nodeType, Expression left, Expression right, out Expression result)
{
result = null;

// Pattern: (obj as Type) != null -> TypeIs(obj, Type)
// Pattern: (obj as Type) == null -> !TypeIs(obj, Type)
if (left.NodeType != ExpressionType.TypeAs || left is not UnaryExpression typeAs || !IsNullConstant(right))
return false;

switch (nodeType)
{
case ExpressionType.NotEqual:
{
result = Expression.TypeIs(typeAs.Operand, typeAs.Type);
return true;
}
case ExpressionType.Equal:
{
result = Expression.Not(Expression.TypeIs(typeAs.Operand, typeAs.Type));
return true;
}
default:
return false;
}
}

public static Expression Optimize(Expression expression)
{
return new GetValueOrDefaultToCoalesceConverter().Visit(new OptimizeExpressionVisitor().Visit(expression));
Expand Down
19 changes: 2 additions & 17 deletions src/DelegateDecompiler/Processor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ static Processor()
ConvertTypeProcessor.Register(processors);
DupProcessor.Register(processors);
InitObjProcessor.Register(processors);
IsinstProcessor.Register(processors);
LdargConstantProcessor.Register(processors);
LdargParameterProcessor.Register(processors);
LdcI4SProcessor.Register(processors);
Expand Down Expand Up @@ -145,6 +146,7 @@ static int ProcessInstruction(ProcessorState state, Instruction instruction)

if (instruction.OpCode == OpCodes.Nop ||
instruction.OpCode == OpCodes.Break ||
instruction.OpCode == OpCodes.Ret ||
instruction.OpCode.FlowControl == FlowControl.Branch)
{
// Do nothing
Expand All @@ -156,23 +158,6 @@ static int ProcessInstruction(ProcessorState state, Instruction instruction)
state.Stack.Push(expression);
return 1;
}
else if (instruction.OpCode == OpCodes.Isinst)
{
var val = state.Stack.Pop();
if (instruction.Next != null && instruction.Next.OpCode == OpCodes.Ldnull &&
instruction.Next.Next != null && instruction.Next.Next.OpCode == OpCodes.Cgt_Un)
{
state.Stack.Push(Expression.TypeIs(val, (Type)instruction.Operand));
// Skip the next two instructions as they're part of this pattern
return 2;
}

state.Stack.Push(Expression.TypeAs(val, (Type)instruction.Operand));
}
else if (instruction.OpCode == OpCodes.Ret)
{
// Return instruction - signal early return
}
else if (processors.TryGetValue(instruction.OpCode, out var processor))
{
processor.Process(state, instruction);
Expand Down
22 changes: 22 additions & 0 deletions src/DelegateDecompiler/Processors/IsinstProcessor.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection.Emit;
using Mono.Reflection;

namespace DelegateDecompiler.Processors
{
internal class IsinstProcessor : IProcessor
{
public static void Register(Dictionary<OpCode, IProcessor> processors)
{
processors.Register(new IsinstProcessor(), OpCodes.Isinst);
}

public void Process(ProcessorState state, Instruction instruction)
{
var val = state.Stack.Pop();
state.Stack.Push(Expression.TypeAs(val, (Type)instruction.Operand));
}
}
}