public CilExpression Translate(RecompilerContext context, ILInstructionExpression expression) { switch (expression.OpCode.Code) { case ILCode.PUSHR_OBJECT: case ILCode.PUSHR_BYTE: case ILCode.PUSHR_WORD: case ILCode.PUSHR_DWORD: case ILCode.PUSHR_QWORD: return(CompileRegisterPush(context, expression)); case ILCode.PUSHI_DWORD: return(new CilInstructionExpression(CilOpCodes.Ldc_I4, unchecked ((int)(uint)expression.Operand)) { ExpressionType = context.TargetImage.TypeSystem.Int32 }); case ILCode.PUSHI_QWORD: return(new CilInstructionExpression(CilOpCodes.Ldc_I8, unchecked ((long)(ulong)expression.Operand)) { ExpressionType = context.TargetImage.TypeSystem.Int64 }); default: throw new ArgumentOutOfRangeException(); } }
private bool TryOptimiseToXor(MatchResult matchResult, ILInstructionExpression expression) { var lefts = matchResult.Captures["left"]; var rights = matchResult.Captures["right"]; if (((ILVariableExpression)lefts[0]).Variable == ((ILVariableExpression)lefts[1]).Variable && ((ILVariableExpression)rights[0]).Variable == ((ILVariableExpression)rights[1]).Variable) { // Unregister remaining variable references. ((ILVariableExpression)lefts[1]).Variable = null; ((ILVariableExpression)rights[1]).Variable = null; // Replace with XOR pseudo opcode. var newExpression = new ILInstructionExpression( expression.OriginalOffset, ILOpCodes.__XOR_DWORD, null, VMType.Dword); newExpression.Arguments.Add((ILExpression)lefts[0].Parent.Remove()); newExpression.Arguments.Add((ILExpression)rights[0].Parent.Remove()); newExpression.FlagsVariable = expression.FlagsVariable; expression.FlagsVariable = null; expression.ReplaceWith(newExpression); return(true); } return(false); }
public override bool VisitInstructionExpression(ILInstructionExpression expression) { // Depth-first to minimize the amount of iterations. bool changed = base.VisitInstructionExpression(expression); MatchResult matchResult; if ((matchResult = NotPattern.Match(expression)).Success) { changed = TryOptimiseToNot(matchResult, expression); } else if ((matchResult = NegIntegerPattern.Match(expression)).Success || (matchResult = NegRealPattern.Match(expression)).Success) { changed = TryOptimiseToNeg(matchResult, expression); } else if ((matchResult = AndPattern.Match(expression)).Success) { changed = TryOptimiseToAnd(matchResult, expression); } else if ((matchResult = OrPattern.Match(expression)).Success) { changed = TryOptimiseToOr(matchResult, expression); } else if ((matchResult = XorPattern.Match(expression)).Success) { changed = TryOptimiseToXor(matchResult, expression); } else if ((matchResult = SubPattern.Match(expression)).Success) { changed = TryOptimiseToSub(matchResult, expression); } return(changed); }
public override CilExpression Translate(RecompilerContext context, ILInstructionExpression expression) { var result = base.Translate(context, expression); result.ExpressionType = null; return(result); }
public CilExpression Translate(RecompilerContext context, ILInstructionExpression expression) { CilOpCode code; switch (expression.OpCode.Code) { case ILCode.SIND_PTR: code = CilOpCodes.Stind_I; break; case ILCode.SIND_BYTE: code = CilOpCodes.Stind_I1; break; case ILCode.SIND_WORD: code = CilOpCodes.Stind_I2; break; case ILCode.SIND_DWORD: code = CilOpCodes.Stind_I4; break; case ILCode.SIND_QWORD: code = CilOpCodes.Stind_I8; break; case ILCode.SIND_OBJECT: code = CilOpCodes.Stind_Ref; break; default: throw new ArgumentOutOfRangeException(nameof(expression)); } var value = (CilExpression)expression.Arguments[0].AcceptVisitor(context.Recompiler); var destination = (CilExpression)expression.Arguments[1].AcceptVisitor(context.Recompiler); switch (destination.ExpressionType) { case PointerTypeSignature pointerType: value.ExpectedType = pointerType.BaseType; break; case ByReferenceTypeSignature byRefType: value.ExpectedType = byRefType.BaseType; break; } return(new CilInstructionExpression(code, null, destination, value) { ExpressionType = null }); }
public void VisitInstructionExpression(ILInstructionExpression expression) { foreach (var argument in expression.Arguments) { argument.AcceptVisitor(this); } if (_offsets.TryGetValue(expression.OriginalOffset, out var variable)) { expression.FlagsVariable = variable; variable.ImplicitAssignments.Add(expression); } }
public virtual CilExpression Translate(RecompilerContext context, ILInstructionExpression expression) { if (!SupportedOpCodes.Contains(expression.OpCode.Code)) { throw new NotSupportedException(); } var result = new CilInstructionExpression(); // Copy instructions foreach (var instruction in NewInstructions) { result.Instructions.Add(new CilInstruction(0, instruction.OpCode, instruction.Operand)); } // Create arguments for (var i = 0; i < expression.Arguments.Count; i++) { // Convert argument. var argument = expression.Arguments[i]; var cilArgument = (CilExpression)argument.AcceptVisitor(context.Recompiler); // Check type. cilArgument.ExpectedType = expression.OpCode.StackBehaviourPop .GetArgumentType(i) .ToMetadataType(context.TargetImage); // Convert if necessary, and add to argument list. result.Arguments.Add(cilArgument); } // Determine expression type from opcode. if (expression.OpCode.StackBehaviourPush != ILStackBehaviour.None) { result.ExpressionType = expression.OpCode.StackBehaviourPush .GetResultType() .ToMetadataType(context.TargetImage); } result.ShouldEmitFlagsUpdate = expression.IsFlagDataSource; if (expression.IsFlagDataSource) { result.AffectedFlags = expression.OpCode.AffectedFlags; result.InvertedFlagsUpdate = InvertedFlagsUpdate; } return(result); }
private static bool TryOptimiseToNot(MatchResult matchResult, ILInstructionExpression expression) { var(left, right) = GetOperands(matchResult); if (left.Variable == right.Variable) { // Unregister one of the variable uses. right.Variable = null; // Replace with NOT pseudo opcode. var newExpression = new ILInstructionExpression( expression.OriginalOffset, expression.OpCode.Code switch { ILCode.NOR_DWORD => ILOpCodes.__NOT_DWORD, ILCode.NOR_QWORD => ILOpCodes.__NOT_QWORD, _ => throw new ArgumentOutOfRangeException(nameof(expression)) },
public CilExpression Translate(RecompilerContext context, ILInstructionExpression expression) { var callMetadata = (CallAnnotation)expression.Annotation; // Convert entrypoint address to physical method def. var method = context.ExportResolver.ResolveMethod(callMetadata.Function.EntrypointAddress); var methodSig = ((MethodSignature)method.Signature); // Create call instruction. CilExpression result = new CilInstructionExpression(CilOpCodes.Call, method, context.RecompileCallArguments(method, expression.Arguments.Skip(1).ToArray(), VMECallOpCode.CALL)) { ExpressionType = methodSig.ReturnType }; // Make sure the resulting object is converted to an unsigned integer if necessary. return(result); }
private bool TryOptimiseToSub(MatchResult matchResult, ILInstructionExpression expression) { var(left, right) = GetOperands(matchResult); // Replace with SUB pseudo opcode. var newExpression = new ILInstructionExpression( expression.OriginalOffset, ILOpCodes.__SUB_DWORD, null, VMType.Dword); newExpression.Arguments.Add((ILExpression)left.Parent.Remove()); newExpression.Arguments.Add((ILExpression)right.Parent.Remove()); newExpression.FlagsVariable = expression.FlagsVariable; expression.FlagsVariable = null; expression.ReplaceWith(newExpression); return(true); }
public override bool VisitInstructionExpression(ILInstructionExpression expression) { // Any push expression that pushes the same type as its argument is superfluous. bool changed = base.VisitInstructionExpression(expression); var match = PushPattern.Match(expression); if (match.Success) { var expr = (ILExpression)match.Captures["expr"][0]; if (expression.ExpressionType == expr.ExpressionType) { expression.ReplaceWith(expr.Remove()); changed = true; } } return(changed); }
private static bool TryOptimiseToNot(ILInstructionExpression expression, MatchResult matchResult) { var(left, right) = GetOperands(matchResult); if (left.Variable == right.Variable) { // Unregister one of the variable uses. right.Variable = null; // Replace with NOT pseudo opcode. var newExpression = new ILInstructionExpression( expression.OriginalOffset, ILOpCodes.__NOT_DWORD, null, VMType.Dword); newExpression.Arguments.Add((ILExpression)left.Parent.Remove()); newExpression.FlagsVariable = expression.FlagsVariable; expression.FlagsVariable = null; expression.ReplaceWith(newExpression); return(true); } return(false); }
public virtual bool VisitInstructionExpression(ILInstructionExpression expression) { return(TryOptimiseArguments(expression)); }
private static CilExpression CompileRegisterPush(RecompilerContext context, ILInstructionExpression expression) { var cilExpression = (CilExpression)expression.Arguments[0].AcceptVisitor(context.Recompiler); var resultType = expression.OpCode.StackBehaviourPush.GetResultType(); if (cilExpression is CilUnboxToVmExpression) { // HACK: Unbox expressions unbox the value from the stack, but also convert it to their unsigned // variant and box it again into an object. We need to unpack it again, however, we do not // know the actual type of the value inside the box, as this is determined at runtime. // // For now, we just make use of the Convert class provided by .NET, which works but would rather // see a true "native" CIL conversion instead. MethodBase convertMethod; switch (resultType) { case VMType.Byte: convertMethod = typeof(Convert).GetMethod("ToByte", new[] { typeof(object) }); break; case VMType.Word: convertMethod = typeof(Convert).GetMethod("ToUInt16", new[] { typeof(object) }); break; case VMType.Dword: convertMethod = typeof(Convert).GetMethod("ToUInt32", new[] { typeof(object) }); break; case VMType.Qword: convertMethod = typeof(Convert).GetMethod("ToUInt64", new[] { typeof(object) }); break; default: throw new ArgumentOutOfRangeException(); } cilExpression.ExpectedType = context.TargetImage.TypeSystem.Object; cilExpression = new CilInstructionExpression( CilOpCodes.Call, context.ReferenceImporter.ImportMethod(convertMethod), cilExpression); } if (resultType == VMType.Object) { if (cilExpression.ExpressionType.IsValueType) { if (cilExpression is CilInstructionExpression instructionExpression && instructionExpression.Instructions.Count == 1 && instructionExpression.Instructions[0].IsLdcI4 && instructionExpression.Instructions[0].GetLdcValue() == 0) { cilExpression = new CilInstructionExpression(CilOpCodes.Ldnull); } else { // If expression returns a value type, we have to box it to an object. cilExpression = new CilInstructionExpression(CilOpCodes.Box, context.ReferenceImporter.ImportType(cilExpression.ExpressionType.ToTypeDefOrRef()), cilExpression); } } else { // Use the reference type of the expression instead of System.Object. cilExpression.ExpressionType = cilExpression.ExpressionType; } }
public CilExpression Translate(RecompilerContext context, ILInstructionExpression expression) { return(new CilInstructionExpression(CilOpCodes.Nop)); }
public string VisitInstructionExpression(ILInstructionExpression expression) => $"{expression.OpCode} {expression.Operand}";
public CilExpression Translate(RecompilerContext context, ILInstructionExpression expression) { var arguments = expression.Arguments .Select(a => (CilExpression)a.AcceptVisitor(context.Recompiler)) .ToArray(); CilOpCode opCode; switch (expression.OpCode.Code) { case ILCode.__EQUALS_OBJECT: opCode = CilOpCodes.Ceq; break; case ILCode.__EQUALS_R32: case ILCode.__EQUALS_R64: case ILCode.__EQUALS_DWORD: case ILCode.__EQUALS_QWORD: opCode = CilOpCodes.Ceq; break; case ILCode.__GT_R32: case ILCode.__GT_R64: opCode = CilOpCodes.Cgt; break; case ILCode.__GT_DWORD: case ILCode.__GT_QWORD: opCode = CilOpCodes.Cgt_Un; break; case ILCode.__LT_R32: case ILCode.__LT_R64: opCode = CilOpCodes.Clt; break; case ILCode.__LT_DWORD: case ILCode.__LT_QWORD: opCode = CilOpCodes.Clt_Un; break; default: throw new ArgumentOutOfRangeException(nameof(expression)); } var argumentType = expression.OpCode.StackBehaviourPop.GetArgumentType(0) .ToMetadataType(context.TargetModule) .ToTypeSignature(); var result = new CilInstructionExpression(opCode) { ExpressionType = context.TargetModule.CorLibTypeFactory.Boolean }; foreach (var argument in arguments) { argument.ExpectedType = argumentType; result.Arguments.Add(argument); } return(result); }